ECMAScript中,引用类型是一种数据结构,用来描述对象的属性和方法。对象则是某个引用类型的实例,可用new
操作符跟一个构造函数创建新对象。
Object 类型
创建Object实例:
构造函数
var cat = new Object();
cat.name = "cat";
var cat = Object();
cat.name = "cat";
对象字面量
var cat = {
name: "cat",
"age": 18
}
使用这种方式创建不会调用Object()
构造函数
属性名之间用逗号相隔,最后一个属性后面不应该有逗号,属性名可以是字符串。
书中还提到了当需要向一个函数中传入大量可选参数时(可选参数可以是函数更加灵活),使用对象字面量是一个很好的选择,因为它不仅代码简单,也可以显示封装性,例如:
function displayInfo(args) {
var output = "";
if (typeof args.name == "string"){
output += "Name: " + args.name + "\n";
}
if (typeof args.age == "number") {
output += "Age: " + args.age + "\n";
}
alert(output);
}
displayInfo({
name: "Nicholas",
age: 29
});
displayInfo({
name: "Greg"
});
访问对象属性
使用两种方式可以访问对象属性:
- 点表示法
- 方括号
比如:
cat.name;
cat["name"];
当对象名是变量,或包含会引起语法错误的字符(比如空格),或者包含非字母非数值时,只能使用方括号(书中还提到了关键字和保留字,笔者记得它们只是不能用作标识符,而且试了好多,发现都可以作为属性名),比如:
var key = "name";
cat[key]; // cat
cat["&key"] = "key"];
cat["&key"]; / /key
cat["first name"] = "cat";
cat["first name"]; // cat
Array 类型
ECMAScript数组每一项可以保存任何类型的数据,大小可以动态调整,之后会举相应的例子。
创建数组
构造函数
var array1 = new Array();
var array2 = new Array(10);
var array3 = Array();
var array4 = new Array("sue", 18, {"birth": "1993-10-24"});
由上述例子可以看出,使用构造函数创建数组时,可以不传参,即创建一个空数组(长度为0),可以传入不小于0的整数作为长度,可以不使用new
操作符,每一项都可以使用任何数据类型。
数组字面量
var array1 = []; //empty array, length 0
var array2 = ["first", "second", "third"];
使用这种方式创建不会调用Array()
构造函数
由于IE8及之前版本与其他浏览器表现不一致,不建议使用以下方式创建:
var array3 = [1, 2,];//IE 8 length is 3; other, length is 2
var array4 = [,,,,]; //IE 8 length is 5; other, length is 4
访问数组
var array = [1, 2, 3];
array[0]; //1
array[2] = 4; // 4
array[2]; // 4
array[5] = 10; // 10
array[5]; //10
array.length; //6
array.length = 10; // 10
array[9]; // undefined
array.length = 1;
array[1]; // undefined
array[12]; //undefined
由上述例子可以看出,数组的索引是从0开始的,最后一个值的索引为length-1
,如果给索引超出length-1
的数组项赋值,那么数组长度会延长至index+1
,如果直接更改数组长度,可以在末尾移除项或添加项,可以通过给指定项赋值来改变指定项的值,如果读取索引超出length-1
的数组项,将返回undefined
,可以使用以下方式在数组的末尾添加一项:
var array = [1,2,3];
array[array.length] = 4;
array[3]; //4
数组中最多可以包含4 294 967 295项。
检测数组
instanceof
如果要判断的数组与Array
构造函数拥有同一个全局作用域,我们可以使用
var array = [1, 2, 3];
array instanceof Array; // true
我们知道,instanceof
其实是做了如下判断:
array.constructor==Array
举个例子:
index.html(部分)
<iframe name="childframe" src="Child.html"></iframe>
<script type="text/javascript">
window.onload = function () {
array= [1, 2, 3];
var result = window.frames[0].search(array);
console.log(window.frames[0].window === window); //false
};
</script>
child.html(部分)
<script type="text/javascript">
search: function (array) {
var result = array instanceof Array;
console.log(result, array.constructor === Array); // false, false
}
</script>
可以看出index.html中的window
与Child.html中的window
并不相同,那么array
也不是Child.html中Array
的实例。
Array.isArray()
在IE9+、Firefox 4+、Safari 5+、Opera 10.5+和Chrome,这些浏览器中,为了解决上述问题,新增了Array.isArray()
方法
var array = [1, 2, 3];
Array.isArray(array); // true
prototype.call()
Object.prototype.toString.call(array)=='[object Array]'
转换方法
toString
调用每一项的toString()
方法,然后用逗号连接起来。
array.toString(); //"1,2,3"
valueOf
不进行转换,返回原数组
toLocaleString
调用每一项的toLocaleString()
方法,然后用逗号连接起来。
join
调用每一项的toString()
方法,然后使用给定字符连接起来。
array.join(); //"1,2,3"
array.join("||"); //"1||2||3"
undefined
和null
项在toString()
toLocaleString()
valueOf
时,变成空值""
。
栈方法
提供了模拟栈数据结构先入后出规则的两个方法。
pop
移除数组的最后一项,使数组的长度减1,并返回被移除的项。
push
向数组尾部添加任意数量的项,并返回数组长度。
var array = [1, 2, 3];
array.push(4, 5); //5
array.pop(); //5
队列方法
提供了模拟队列数据结构先入先出访问规则的两个方法。
正向队列 shift()
+ push()
shift()
可以移除数组的第一项,并返回该项。
反向队列 unshift()
+ pop()
unshift()
可以在数组前端插入任意个数的项并返回新数组的长度。
重排序
reserve()
将数组反转,比如:
var array = [1, 2, 3];
array.reverse(); // [3, 2, 1]
sort()
由于reverse
只能单一地将数组反转,不够灵活,因此又有了sort()
。默认情况下,sort()
按从小到大的顺序给数组排序,排序时,首先对每一项执行toString()
,然后比较字符串的大小,即sort()
无论何时都是在比较字符串大小,即使数组项里全是数值。
var array = [1, 2, 10, 3, 23];
array.sort(); // [1, 10, 2, 23, 3]
sort()
可以接收比较函数为参数来指定比较逻辑,比较函数接收两个参数,当第一个应该在第二个之后时,返回大于0的数值,两者相等时,返回0,第二个应该在第二个之前时,返回小于0的数值,比如我们声明一个可以按数值由大到小排序的比较函数:
function compare(num1, num2) {
if(num1 > num2) {
return 1;
} else if(num1 === num2) {
return 0;
} else {
return -1;
}
}
array.sort(compare); // [1, 2, 3, 10, 23]
当数据项全部是数值或者对每一项调用其valueOf()
方法都返回一个数值,那么我们可以简化以上逻辑:
function compare(num1, num2) {
return num1 - num2;
}
操作方法
concat
- 如果不带参数,返回当前数组的拷贝(新数组)
- 如果参数为数组,首先拷贝当前数组,然后将参数与当前数组连接生成新数组
- 如果参数不是数组,首先拷贝当前数组,然后将参数放到新数组的末端。
concat()
在拷贝出来的新数组进行操作,不会影响到原数组,举几个例子:
var array = [1, 2, 3];
array.concat(); // [1, 2, 3]
array.concat([2,3,4]); // [1, 2, 3, 2, 3, 4];
array.concat(5); // [1, 2, 3, 5]
array.concat(4, 5, [6, 7, 8]); //[1,2 ,3, 4, 5, 6, 7, 8]);
array; //[1, 2, 3]
slice
slice()
基于给定数组的片段返回新数组,不会影响原来的数组。
- 如果传入一个参数,则截取从给定位置开始,到数组末尾的所有项
- 如果有两个参数,则它们分别作为起始位置,返回之间(包括起始项但不包括结尾项)的所有项。如果参数为负数,则使用数组长度加上这个负数来替代这个参数
var array = [1, 2, 3];
array.slice(2); // [3]
array.slice(3); // []
array.slice(0, 2); // [1, 2]
array.slice(3, 2); //[]
array.slice(-3, -2); //相当于array.slice(0, 1) 返回[1]
array; //[1, 2, 3]
splice
- 删除项。指定两个参数,即删除的起始位置(如果项数大于0,起始位置是被第一个删除的项)和删除的项数,返回被删除的项组成的数组。
- 插入项。指定多个参数,第一个是插入的开始位置(第一个插入项将获得的索引位置)、0(删除0项)、插入的项(可多个)。
- 替代项。指定多个参数,第二个是替代的开始位置、删除的项数、插入的项(可多个,插入项的数量不用跟删除项数保持一致)。
以上方法返回的都是被删除的项组成的数组,举一些例子:
var array = [1, 2, 3, 4];
array.splice(0, 1); // [1]
array; //[2, 3, 4]
array.splice(1, 0, 4, 5); //[]
array; //[2, 4, 5, 3, 4]
array.splice(2, 2, 7, 8, 9); //[5, 3]
array; //[2, 4, 7, 8, 9]
位置方法
indexOf
从数组开头向后查找
lastIndexOf
从数组末尾向前查找
二者都接收2个参数,查找的项,和查找起点(可选),如果找不到,返回-1,只要找到与查找项全等的项,则返回其索引。
var array = [1, 2, 3, 4, 3];
array.indexOf(3); //2
array.lastIndexOf(3); //4
array.indexOf(3, 3); //4
array.indexOf(3, 2); //2
array.lastIndexOf(3, 1); // -1
array.lastIndexOf(3, 3); //2
支持这两个方法的浏览器包括:IE9+、Firefox 2+、Safari 3+、Opera 9.5+和Chrome。
迭代方法
以下每个方法接收两个参数,第一个是对每一项执行的函数,第二个是该函数的this
(作用域),该函数接收三个参数,第一个是当前项,第二个是当前项的索引,第三个是数组。
every()
对每一项运行给定函数,如果都返回true
,则返回true
。
some()
对每一项运行给定函数,如果存在返回true
的项,则返回true
。
filter()
对每一项运行给定函数,返回该函数会返回true 的项组成的数组。
forEach()
对每一项运行给定函数,无返回值。
map()
对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
支持这些迭代方法的浏览器有IE9+、Firefox 2+、Safari 3+、Opera 9.5+和Chrome。
举一些例子:
function function1(value, index, array) {
return value > 2;
}
function function2(value, index, array) {
return value * 2;
}
function function3(value, index, array) {
array[index] = value * 2;
}
var array = [1, 2, 3, 4, 5];
array.every(function1, this); // false
array; // [1, 2, 3, 4, 5]
array.some(function1, this); // true
array; // [1, 2, 3, 4, 5]
array.filter(function1, this); // [3, 4, 5]
array; // [1, 2, 3, 4, 5]
array.forEach(function2, this); //undefined
array; //[1, 2, 3, 4, 5]
array.map(function2, this); //[2, 4, 6, 8, 10]
array; //[1, 2, 3, 4, 5]
array.forEach(function3, this); // undefined
array; [2, 4, 6, 8, 10]
这五个方法传入的函数都可以获取整个数组和相应的索引,都是可以更改数组的。
归并方法
以下两个方法都会遍历数组所有项,得出最后一个返回值
-
reduce()
从第一个遍历到最后 -
reduceRight()
从最后一个遍历到第一个
两个方法都接收两个参数,对每一项执行的函数,归并初始值(可选),传入的函数接收四个参数,前一项的值,当前项的值,index,数组,函数每次执行的返回值都将作为下一次执行的第一个参数,第一次迭代发生在第二项,即第一个参数是第一项,第二个参数是第二项。
举一个求和的例子:
function sum(preV, curV, index, array) {
return preV + curV;
}
var array = [1, 2, 3, 4];
array.reduce(sum); //10
支持这两个归并函数的浏览器有IE9+、Firefox 3+、Safari 4+、Opera 10.5 和Chrome。