1.定义
数组(array)是按次序排列的一组值。每个值的位置都有编号(从0开始),整个数组用方括号表示。
var arr = ['a', 'b', 'c'];
上面代码中的a、b、c就构成一个数组,两端的方括号是数组的标志。a是0号位置,b是1号位置,c是2号位置。
数组也可以先定义后赋值
var arr = [];
arr[0] = 'a';
arr[1] = 'b';
arr[2] = 'c';
数组的每一项可以保存任何类型的数据
var arr = [
'hello',
34,
{a:1},
[1, 2, 3],
function(){return true;}
];
上述代码中,数组的每一项分别是字符串,数值,对象,数组以及函数。
数组的本质
console.log(typeof arr);//object
上面代码表明,typeof运算符认为数组的类型就是对象。
数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2…)。
由于数组成员的键名是固定的(默认总是0、1、2…),因此数组不用为每个元素指定键名,而对象的每个成员都必须指定键名。JavaScript 语言规定,对象的键名一律为字符串,所以,数组的键名其实也是字符串。之所以可以用数值读取,是因为非字符串的键名会被转为字符串。
console.log(arr[0]);//'a'
console.log(arr['0']);//'a'
上面代码分别用数值和字符串作为键名,结果都能读取数组。原因是数值键名被自动转为了字符串。
注意,这点在赋值时也成立。一个值总是先转成字符串,再作为键名进行赋值。
结合对象访问成员的方法,点方法和方括号表示法。可以理解为何数组只能用方括号表示法
var arr = [1, 2, 3];
arr.0 //报错
上面代码中,arr.0的写法不合法,因为单独的数值不能作为标识符(identifier)。所以,数组成员只能用方括号arr[0]表示(方括号是运算符,可以接受数值)。
length
数组的length属性不是只读的,可以通过设置这个属性,从数组的末尾移除项或添加新项
var arr = ['a', 'b', 'c'];
arr.length = 2;
console.log(arr[2]);//undefined
在上述例子中,arr本来有3个值,通过将length属性设置为2则会移除length大于2(键名大于1)的项,再访问arr[2]就会显示undefined。同理,如果将length属性设置为大于数组项数的值,则新增的每一项都会取得undefined值
var arr = ['a', 'b', 'c'];
arr.length = 4;
console.log(arr[3]);//undefined
利用length属性也可以方便地在数组末尾添加新项
var arr = ['a', 'b', 'c'];
arr[arr.length] = 'd';
arr[arr.length] = 'e';
arr//['a', 'b', 'c', 'd', 'e']
2.Array.isArray( )
Array.isArray( )方法返回一个布尔值,表示参数是否为数组。它可以弥补typeof运算符的不足。
console.log(Array.isArray(arr));//true
console.log(typeof arr);//object
上面代码中,typeof运算符只能显示数组的类型是Object,而Array.isArray方法可以识别数组。
3.转换方法
valueOf( )
valueOf方法是一个所有对象都拥有的方法,表示对该对象求值。不同对象的valueOf方法不尽一致,数组的valueOf方法返回数组本身。
var arr = ["a", "b", "c"];
console.log(arr.valueOf());//["a", "b", "c"]
toString( )
toString方法也是对象的通用方法,数组的toString方法返回数组的字符串形式。
var arr = ["a", "b", "c"];
console.log(arr.toString());//"a,b,c"
4.push( )与pop( )(栈方法)
push( )
push( )方法可以接受任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。注意,该方法会改变原数组。
var arr = [];
arr.push(1);//1
arr.push('a');//2
arr.push(true,{});//4
arr//[1, 'a', true, {}]
上面代码使用push方法,往数组中添加了四个成员。
pop( )
pop( )方法从数组末尾移除最后一项,减少数组的length值,然后返回移除的项。注意,该方法会改变原数组。
var arr = ["a", "b", "c"];
arr.pop();//"c"
arr//["a", "b"]
对空数组使用pop方法,不会报错,而是返回undefined。
[].pop() // undefined
结合使用push和pop构成“后进先出”的栈结构(stack)
var arr = [];
arr.push(1, 2);
arr.push(3);
arr.pop();
arr // [1, 2]
上面代码中,3是最后进入数组的,但是最早离开数组。(后进先出)
5.shift( )与unshift( )
shift( )
shift()方法用于删除数组的第一个元素,并返回该元素。注意,该方法会改变原数组。
var a = ['a', 'b', 'c'];
a.shift() // 'a'
a // ['b', 'c']
结合使用shift和push就构成了“先进先出”的队列结构(queue)。
unshift( )
unshift()方法用于在数组的第一个位置添加任意个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。
var arr = ['b', 'c'];
arr.unshift('a');
arr//['a', 'b', 'c']
unshift()方法可以接受多个参数,这些参数都会添加到目标数组头部。
var arr = ['c', 'd'];
arr.unshift('a', 'b');
arr//['a', 'b', 'c', 'd']
6.reverse( )与sort( )
reverse( )
reverse方法会反转排列数组元素,返回改变后的数组。注意,该方法将改变原数组。
var arr = ["a", "b", "c"];
arr.reverse();//["c", "b", "a"]
sort( )
sort方法对数组成员进行排序,默认是按照字典顺序排序。排序后,原数组将被改变。
['d', 'c', 'b', 'a'].sort()
// ['a', 'b', 'c', 'd']
[4, 3, 2, 1].sort()
// [1, 2, 3, 4]
[11, 101].sort()
// [101, 11]
[10111, 1101, 111].sort()
// [10111, 1101, 111]
上面代码的最后两个例子,需要特殊注意。sort方法不是按照大小排序,而是按照字典顺序。也就是说,数值会被先转成字符串,再按照字典顺序进行比较,所以101排在11的前面。
如果想让sort方法按照自定义方式排序,可以传入一个函数作为参数。
[10111, 1101, 111].sort(function (a, b) {
return a - b;
})
// [111, 1101, 10111]
上面代码中,sort的参数函数本身接受两个参数,表示进行比较的两个数组成员。如果该函数的返回值大于0,表示第一个成员排在第二个成员后面;其他情况下,都是第一个元素排在第二个元素前面。
[
{ name: "张三", age: 30 },
{ name: "李四", age: 24 },
{ name: "王五", age: 28 }
].sort(function (o1, o2) {
return o1.age - o2.age;
})
// [
// { name: "李四", age: 24 },
// { name: "王五", age: 28 },
// { name: "张三", age: 30 }
// ]
7.concat( )与slice( ),spcice( )
concat( )
concat方法用于多个数组的合并。它将新数组的成员,添加到原数组成员的后部,然后返回一个新数组,原数组不变。
var arr1 = [1, 2, 3, 4];
var arr2 = arr1.concat(['a','b']);
console.log(arr2);//[1, 2, 3, 4, "a", "b"]
slice( )
slice方法用于提取目标数组的一部分,返回一个新数组,原数组不变。
它的第一个参数为起始位置(从0开始),第二个参数为终止位置(但该位置的元素本身不包括在内)。如果省略第二个参数,则一直返回到原数组的最后一个成员。
var arr1 = ['a', 'b', 'c', 'd'];
var arr2 = arr1.slice(1,3);
console.log(arr2);//["b", "c"]
var arr3 = arr1.slice(1);
console.log(arr3);//["b", "c", "d"]
var arr4 = arr1.slice();
console.log(arr4);//["a", "b", "c", "d"]
上面代码中,最后一个例子slice没有参数,实际上等于返回一个原数组的拷贝。
如果slice方法的参数是负数,则表示倒数计算的位置。
var arr5 = arr1.slice(-3);
console.log(arr5);//["b", "c", "d"]
var arr6 = arr1.slice(-3,-2);
console.log(arr6);//["b"]
splice( )
splice方法用于删除原数组的一部分成员,并可以在删除的位置添加新的数组成员,返回值是被删除的元素。注意,该方法会改变原数组。
splice的第一个参数是删除的起始位置(从0开始),第二个参数是被删除的元素个数。如果后面还有更多的参数,则表示这些就是要被插入数组的新元素。
var arr = ['a', 'b', 'c', 'd', 'e'];
console.log(arr.splice(2,3));//["c", "d", "e"]
console.log(arr);//["a", "b"]
上面代码从原数组2号位置,删除了3个数组成员。
var arr = ['a', 'b', 'c', 'd', 'e'];
console.log(arr.splice(2,3,'f',5,{name:'Ricardo'}));//["c", "d", "e"]
console.log(arr);//["a", "b", "f", 5, {name:'Ricardo'}]
上面代码除了删除成员,还插入了3个新成员。
起始位置如果是负数,就表示从倒数位置开始删除。
var arr = ['a', 'b', 'c', 'd', 'e'];
console.log(arr.splice(-3,3));//["c", "d", "e"]
console.log(arr);//["a", "b"]
上面代码表示,从倒数第3个位置c开始删除3个成员。
如果只是单纯地插入元素,splice方法的第二个参数可以设为0。
var arr = ['a', 'b', 'd', 'e'];
console.log(arr.splice(2,0,'c'));//[]
console.log(arr);//["a", "b", "c", "d", "e"]
8.indexOf( )与lastIndexOf( )
indexOf( )
indexOf方法返回给定元素在数组中第一次出现的位置,如果没有出现则返回-1。
var arr = ['a', 'b','e','d', 'e'];
console.log(arr.indexOf('e'));//2
console.log(arr.indexOf('c'));//-1
indexOf方法还可以接受第二个参数,表示搜索的开始位置。
var arr = ['a', 'b','e','d', 'e'];
console.log(arr.indexOf('e'));//2
console.log(arr.indexOf('e',3));//4
上述代码从头开始则返回2,从第三个位置开始则返回第二个e所在的位置4
lastIndexOf( )
lastIndexOf方法返回给定元素在数组中最后一次出现的位置,如果没有出现则返回-1。
var arr = ['a', 'b','e','d', 'e'];
console.log(arr.indexOf('e'));//2
console.log(arr.lastIndexOf('e'));//4
上述代码中,'e’出现的第一次和最后一次位置分别为2和4
9.every( )与some( ),filter( ),map( ),forEach( )
这5个方法都接收两个参数:要在每一项上运行的函数,以及(可选)运行该函数的作用域对象
传入这5个迭代方法的函数都会接收三个参数:数组项的值(item),该项在数组的位置(index),数组本身(array)
every( )与some( )
every( )对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true
some( )对数组中的每一项运行给定函数,如果该函数对任一一项都返回true,则返回true
var arr = [1, 2, 3, 4, 5, 6]
var everyResult = arr.every(function(item,index,array){
return (item > 2);
});
var someResult = arr.some(function(item,index,array){
return (item > 2);
});
console.log(everyResult);//false
console.log(someResult);//true
上述代码传入的函数,给值大于2的项返回true,给值小于2的项返回false,只有部分项满足条件,所以every( )方法返回false,但some( )返回true。
filter( )
filter( )对数组中的每一项运行给定函数,返回该函数返回值为true的项组成的数组
var arr = [1, 2, 3, 4, 5, 6]
var filterResult = arr.filter(function(item,index,array){
return (item > 2);
});
console.log(filterResult);//[3, 4, 5, 6]
map( )
map( )对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组
var arr = [1, 2, 3, 4, 5, 6]
var mapResult = arr.map(function(item,index,array){
return item*2;
});
console.log(mapResult);//[2, 4, 6, 8, 10, 12]
forEach( )
forEach方法与map方法很相似,也是对数组的所有成员依次执行参数函数。但是,forEach方法不返回值,只用来操作数据。这就是说,如果数组遍历的目的是为了得到返回值,那么使用map方法,否则使用forEach方法。
var arr = [1, 2, 3, 4, 5, 6]
arr.forEach(function(item, index, array){
//执行某些操作
});
10.reduce( )与reduceRight( )
reduce方法和reduceRight方法依次处理数组的每个成员,最终累计为一个值。它们的差别是,reduce是从左到右处理(从第一个成员到最后一个成员),reduceRight则是从右到左(从最后一个成员到第一个成员),其他完全一样。
这两个方法都接收两个参数:一个在每一项上调用的函数和(可选)作为归并基础的初始值
该函数接受以下四个参数。
累积变量,默认为数组的第一个成员
当前变量,默认为数组的第二个成员
当前位置(从0开始)
原数组
这四个参数之中,只有前两个是必须的,后两个则是可选的。
这个函数的返回值都会作为第一个参数返回给下一项
var arr = [1, 2, 3, 4, 5];
var sum = arr.reduce(function(prev, cur, index, array){
return prev + cur
});
console.log(sum)//15
参考资料
- 《JavaScript高级程序设计》
- 阮一峰JavaScript标准参考教程(alpha)