Array类型的数组数量问题
1 | var ar = [,,,]; |
小技巧,利用length在数组的末尾添加新项1
2var colors = ["red","blue"];
colors[color.length] = "black";
join()方法用于给数组提供分隔符以构建字符串
1 | var colors = ["red","green"]; |
栈方法(LIFO):后进先出;队列方法(FIFO):先进先出
方法类比:
方法名称 | 方法作用 |
---|---|
push() | 从数组后方依次添加 |
unshift() | 从数组前方依次添加 |
pop() | 从数组后方删除最后一个,并返回被删除值 |
shift() | 从数组前删除第一个,并返回第一个被删除的值 |
重排序方法
1 | var values = [0,1,2,10,15]; |
原因:排序时sort将所有数组值均转化为字符串值再拍讯。
解决方法:新建一个compare()方法进行比较1
2
3
4
5
6
7
8
9
10
11
12
13function compare(value1,value2){
if(value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
}
var values = [0,1,5,10,15];
values.sort(compare);
console.log(values); //0,1,5,10,15
操作方法
concat():链接两数组,若不传递参数,则只复制一份,不会额外向原数组增加内容。
slice():复制当前数组,参数为开始和结束位置。1
2
3
4
5var arr = [1,2,3,4,5];
var arr1 = arr.slice(1);
console.log(arr1); //2,3,4,5
var arr2 = arr.slice(1,4);
console.log(arr2); //2,3,4
注:当slice传参为负时,则要加上数组长度,以得到正确结果。
splice():有删除,插入,替换三个作用
删除:splice(要删除的第一项,删除的项数);
插入:splice(起始位置,0,要插入的项);
替换:splice(起始位置,要删除的项,要替换的项);
迭代方法
every():为数组每一次运行给定函数,每一项为true,则返回true。
fliter():为数组的每一项执行给定函数,返回true项组成的数组。
forEach():每一项执行函数,无返回值。
map():为每一项执行函数,返回每次调用结果组成的数组。
some():为每一项执行函数,任意项返回true,则返回true。
归并方法
reduce():迭代数组所有项,构建一个最终返回值。
reduceRight():迭代数组所有项,从最后一个数开始。
函数声明提升
解析器会在代码执行前进行一个函数声明提升的过程,读取并将函数声明添加到执行环境中。1
2
3
4
5
6
7
8console.log(num1(1,2)); //3
console.log(num2(1,2)); //报错
function num1(m , n){
return m + n;
}
num2 = function(m , n){
return m + n;
}
注:要访问函数的指针而不执行函数,则需要在调用时去掉函数的圆括号进行调用。
使用arguments.callee()消除紧密耦合
1 | //这是一个普通的递归函数 |
函数的prototype属性
对于所有属性,prototype属性时保存他们的所有实例方法的真正所在,prototype属性包含两个非继承来的方法:apply()和call()。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15function sum(num1,num2){
return num1 + num2;
}
function callSum1(num1,num2){
return sum.apply(this.arguments); //传入arguments对象
}
function callSum2(num1,num2){
return sum.apply(this,[num1,num2]); //传入数组
}
function callSum3(num1,num2){
return sum.call(this,num1,num2);
}
console.log(callSum1(10,10)); //20
console.log(callSum2(10,10)); //20
console.log(callSum3(10,10)); //20
call和apply的作用相同,当包含函数中接受数组时,apply更加合适。
apply和call的最大用处,是可扩充函数赖以执行的作用域7.1
2
3
4
5
6
7
8window.color = "red";
var o = {color : "blue"};
function sayColor(){
alert(this.color);
}
sayColor(); //red
sayColor(o); //blue
sayColor(window); //red
基本包装类
基本包装类的自用创建的引用类型实例,会在代码执行后立即销毁。1
2
3var s1 = "some test";
s1.color = "red";
colsole.log(s1.color); //undefined
注:直接使用转型函数,则返回相应结果。使用构造函数,则返回相应函数的实例。1
2
3
4
5var value = "25";
var number = Number(value); //使用转型函数
console.log(typeof number); //number
var obj = new Number(value); //使用构造函数
console.log(typeof obj); //Object
注:new会创造一个object对象,new Boolean(false)可判定为true。
数值类型的转换
.toFixed(n):表示转换为几位小数的值。
.toExponential(n):表示转换为几位指数值
.toPreoision(n):表示转换为n位最合适的数
.charAt():输出当前字符串的第n位字符(从0开始)
.charCodeAt():输出当前字符串的第n位字符的ASCII码
.trim():删除前缀和后缀的空格,并返回结果
.toLowerCase():转换为小写
.toUpperCase():转换为大写
.match():查找字符串相匹配的位置(search())的作用相同
.replace():传递两个参数,用后面的参数替换前面的参数
.localeCompare():比较,返回-1,0,1的其中一种
.fromCharCode():接收字符编码,转换为字符串
.eval():相当于一个独立解析器,在其中创建任何变量或函数都不会被提升
typrof()和instanceof()得到的结果不同,如下:
1 | var numberObject = new Number(10); |
面向对象
数据属性
configurable:表示能否通过delete删除属性从而重新定义属性,默认为true。
enumerable:表示能否通过for-in循环返回属性,默认为true。
writable:表示能否修改属性值,默认为true。
value:表示包含这个属性的数据值,默认为undefined。
以上的属性,可以通过` Object.defineProperty()方法进行修改。但是一旦属性定义为不可配置,再调用该方法修改除writable以外的属性,都会导致错误。定义多个属性,可用Object.defineProperties()。
Object.getOwnPropertyDescriptor()方法,可取得给定属性的描述符。
访问器属性
访问器属性不包含属性值,但包含一对getter和setter函数,读取时调用getter,写入时调用setter。
注:在某参数前加“_”表示该参数只能通过对象方法访问。
工厂模式
抽象了创建具体对象的过程,用函数来封装以特定接口创建对象的细节。1
2
3
4
5
6
7
8
9
10
11function createPerson(name,age,job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
}
return o;
}
var person1 = createPerson("changer",18,"Engineer");
函数createPerson()能够根据接受的参数来构建一个包含所有必要信息的person对象,可无数次调用,工厂模式虽然解决了多个相似对象的问题,却没有解决对象识别的问题。
构造函数模式
1 | function Person(name,age,job){ |
构造函数始终都应以一个大写字母开头,非构造函数应以小写字母开头。构造函数的实例都有constructor()属性,该属性指向Person。
构造函数的缺点:每个方法都要在每个实例上重新创建一遍,因此可将函数定义转移到函数外面以解决问题:1
2
3
4
5
6
7
8
9function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
}
function sayName(){
alert(this.name);
}
var person1 = Person("changer","18,"Engineer");
以上做法解决了两个函数做同一件事的问题,但是在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域名不副实,如果要定义多个方法,全部作为全局变量就毫无封装性可言了。
原型模式
注:当原型中有某属性而且实例中也有该属性时,原型中的该属性值就用不到了,也无法被检测出来。1
2
3
4
5
6
7
8
9
10
11
12function Person(){}
Person.prototype = {
name : "Nicholas",
age : 29,
job : "Software Engineer",
sayName : function(){
alert(this.name);
}
}
var friend = new Person();
alert(friend instanceof Person); //true
alert(friend.constructor == Person); //false
以上写法完全重写了默认的prototype对象,因此constructor属性也就变成了新对象的constructor属性,指向Object构造函数。
在浏览器内核兼容ES5的情况下,可在下面增加:1
2
3
4Object.defineProperty(Person.prototype,"constructor",{
enumerable : false,
value : Person
})
该写法改进了在Person.prototype中设置导致enumerable属性被设置为true的问题。
但是原型对象还存在问题:省略了构造函数传递初始化参数这一操作,会使所有实例在默认情况下取得相同值。
混成模式
组合使用了构造函数模式和原型模式,构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。1
2
3
4
5
6
7
8
9
10
11
12
13function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["aa","bb"];
}
Person.prototype = {
constructor : Person;
sayName : function(){
alert(this.name);
}
}
var person1 = new Person("changer",18,"worker");
继承
通过原型链实现继承时,不能使用对象字面量创建原型方法,这样做会重写原型链。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.property = false;
}
SubType.prototype = new SuperType;
//为原型使用字面量添加新方法,会使之前的方法无效
SubType.prototype = {
getSubValue : function(){
return this.subproperty;
}
SomeOtherMeshod :funcion(){
return false;
}
}
var instance = new SubType();
alert(instance.gerSuperValue()); //错误,找不到该方法
原型链的问题:原型链上所有属性都被共享,原型链上的数据可由原型push进行增加。创建子类型的实例时,无法向超类型的构造函数中传递参数。
借用构造函数
在子类型构造函数的内部调用超类型构造函数1
2
3
4
5
6
7
8
9
10
11function SuperType(){
this.colors = ["red","blue","green"];
}
function SubType(){
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1,colors); //red,blue,green,black
var instance2 = new SubType();
console.log(instance2.colors); //red,blue,green
由此可见,因为call()方法创造了一个新的SuperType的作用域,使得两个实例在不同的作用域中进行,从而产生了不同的colors结果。