数组

数组的定义

字面量方式

1
2
3
4
5
var BAT = ['Alibaba', 'Tencent', 'Baidu'];
var students = [{name: 'Bosn', age: 27}, {name: 'Nunnly', age: 3}];

var commasArr1 = [1,,2]; // 1, undefined, 2
var commasArr2 = [,,]; // undefined, undefined, undefined

构造器方式

1
2
3
var arr = new Array();
var arrWithLength = new Array(100); // undefined * 100
var arrLikesLiteral = new Array(true, false, null, 1, 2, "hi"); // [true, false, null, 1, 2, "hi"]

注:new 可以去掉。

数组最多可以容纳 4,294,967,295 (即 2^32-1)项,如果想添加的项数超过这个上限值,就会发生异常。而创建一个初始大小与这个上限值接近的数组,则可能会导致运行时间超长的脚本错误。

用代码验证一下:

1
2
var maxArr1 = new Array(Math.pow(2,32)-1);  // (4294967295) [empty × 4294967295]
var maxArr2 = new Array(Math.pow(2,32)); // Uncaught RangeError: Invalid array length

数组的增删

数组是动态的,无需指定大小

1
var arr0 = [];

增:角标访问

1
2
arr0[0] = 1;
arr0[1] = 2;

几个特殊的增方法:

  • push(最后一个位置增加)
  • length(最后一个位置增加)
  • unshift(第一个位置增加)
1
2
3
arr0.push(3);
arr0[arr0.length] = 4;
arr0.unshift(0);

删:delete

delete(只删除值,位置不会删除,该位置的值变成 undefined)

1
2
3
4
delete arr0[2];
arr0; // [0, 1, undefined, 3, 4]
arr0.length; // 5
2 in arr0; // false

几个特殊的删方法:

  • 删除尾部元素:arr.length -= 1; pop()
  • 删除头部元素:unshift()
1
2
3
4
5
6
7
arr0.length -= 1;
arr0; // [0, 1, undefined, 3]
arr0.pop();
arr0; // [0, 1, undefined]

arr0.shift();
arr0; // [1, undefined]

数组的方法

  • Array.prototype.join()
  • Array.prototype.reverse()
  • Array.prototype.sort()
  • Array.prototype.concat()
  • Array.prototype.slice()
  • Array.prototype.splice()

以下为 ES5 的方法,支持 IE9+:

  • Array.prototype.forEach()
  • Array.prototype.map()
  • Array.prototype.filter()
  • Array.prototype.every()
  • Array.prototype.some()
  • Array.prototype.reduce()
  • Array.prototype.reduceRight()
  • Array.prototype.indexOf()
  • Array.prototype.lastIndexOf()
  • Array.prototype.isArray()

其中,改变原数组的:

shift,unshift,pop,push,reverse,sort,splice (返回被删除数组,无删除则不返回)

不改变原数组的:
join,concat,slice
forEach,map,filter,every,some (ES5)

join 合并

原数组不被修改

1
2
3
var arr1 = [1,2,3];
arr1.join(); // "1,2,3"
arr1.join("_") // "1_2_3"

应用:使用 join() 实现重复某个字符 N 次

1
2
3
4
5
6
function repeatString(str, n){
return new Array(n+1).join(str);
}

console.log(repeatString("a", 3)); // "aaa"
console.log(repeatString("Hi", 3)); // "HiHiHi"

reverse 反向排序

原数组被修改

1
2
3
var arr2 = [1,2,3];
console.log(arr2.reverse()); //[3,2,1]
console.log(arr2); //[3,2,1]

sort 排序

原数组被修改

1
2
var arr3 = ['a','d','b','c'];
console.log(arr3.sort()); // ['a','b','c','d'];

注:sort 默认是按照字母顺序排序的,例如:

1
2
var arr4 = [13,24,51,3]; // 会先转换成字符串再排序
console.log(arr4.sort()); // [13, 24, 3, 51]

如果想自定义比较方法,需要自定义方法

1
2
3
4
5
arr4.sort(function(a,b){
return a-b;
})

// [3,13,24,51]
1
2
3
4
5
6
7
8
9
10
arr5 = [{age:25}, {age:99}, {age:39}]
arr5.sort(function(a,b){
return a.age - b.age;
})

arr5.forEach(function(item){
console.log('age', item.age);
})

//age 25, age 39, age 99

concat 拼接

原数组不被修改

1
2
3
var arr6 = [1,2,3];
arr6.concat(4,5); //[1,2,3,4,5]
arr6; //[1,2,3]

concat 的参数如果为数组,那么数组会被“拉平”,即去掉数组形式

1
2
console.log(arr6.concat([10,11],13)); 
// [1,2,3,10,11,13]

注:去掉数组只能去一层

1
2
console.log(arr6.concat([1,[2,3]]));  
// [1,2,3,1,[2,3]]

slice 剪切

原数组不被修改

slice 方法为左闭右开区间,下例中为下标 1 =< i < 3:

1
2
3
4
var arr7 = [1,2,3,4,5];

arr7.slice(1,3); // [2,3]
arr7.slice(1); // [2,3,4,5]

负数索引表示从后往前的位置,-1 表示倒数第1个位置

1
2
3
arr7.slice(1,-1)  // [2,3,4]
arr7.slice(-4,-3) // [2]
arr7.slice(-3,-4) // []

注:该方法并不会修改数组,而是返回一个与子数组相同的新数组,因此可以用来实现深拷贝。

splice

原数组被修改
语法: splice(index,howmany,item1,…..,itemX)

index - 添加/删除项目的位置
howmany - 要删除的项目数量。如果设置为 0,则不会删除项目。
item1,..,itemX - 可选。向数组添加的新项目。

arr.splice() 的返回值为被删除的元素!

1
2
3
4
5
6
7
8
9
10
11
var arr8 = [1,2,3,4,5]; 
console.log(arr8.splice(2)); //[3,4,5]
console.log(arr8); //[1,2]

arr9 = [1,2,3,4,5];
console.log(arr9.splice(2,2)); //[3,4]
console.log(arr9); //[1,2,5]

arr10 = [1,2,3,4,5];
console.log(arr10.splice(1,1,'a','b')); //[2]
console.log(arr10); //[1,'a','b',3,4,5]

forEach

原数组不被修改

1
2
3
4
5
6
7
8
9
10
11
var arr11 = [1,2,3,4,5]; 
arr11.forEach(function(x, index, a){
console.log(x+'|'+index+'|'+(a == arr11));
})

// 输出:
1|0|true
2|1|true
3|2|true
4|3|true
5|4|true

map

原数组不被修改

1
2
3
4
5
6
7
8
9
var arr12 = [1,2,3,4,5]; 
console.log(arr12.map(function(x){
return x+10;
}));

console.log(arr12);

// [11, 12, 13, 14, 15]
// [1, 2, 3, 4, 5]

filter

原数组不被修改

1
2
3
4
5
6
7
8
var arr13 = [1,2,3,4,5,6,7,8,9,10]; 
console.log(arr13.filter(function(x,index){
return index%3 === 0|| x>=8;
}));
console.log(arr13)

// [1, 4, 7, 8, 9, 10]
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

every

检查数组中的每一个元素是否满足条件,原数组不被修改。

语法:

arr.every(function(eachItem, index, arr), thisValue);

  • eachItem: 必选。数组中每一项的值
  • index: 可选。当前元素的索引值
  • arr: 可选。原数组
  • thisValue: 可选。对象作为该执行回调时使用,传递给函数,用作 “this” 的值。如果省略了 thisValue ,”this” 的值为 “undefined”
1
2
3
4
5
6
7
8
var arr14 = [1,2,3,4,5]; 
console.log(arr14.every(function(x){
return x<10;
})); // true

console.log(arr14.every(function(x){
return x<3;
})); // false

some

检查数组中是否有任意一个元素满足条件,原数组不被修改。

1
2
3
4
5
6
7
console.log(arr14.some(function(x){
return x === 3;
})); // true

console.log(arr14.some(function(x){
return x === 100;
})); // false

reduce & reduceRight

原数组不被修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var arr15 = [1,2,3];
console.log(arr15.reduce(function(x,y){
return x+y;
}));

// 6

console.log(arr15.reduce(function(x,y){
console.log(x + '|' + y);
return x > y ? x : y;
}));

输出:
1|2
2|3
3

console.log(arr15.reduceRight(function(x,y){
console.log(x + '|' + y);
return x > y ? x : y;
}));

输出:
3|2
3|1
3

indexOf & lastIndexOf

原数组不被修改

1
2
3
4
5
6
7
8
9
var arr16 = [1,2,3,2,1]
arr16.indexOf(2); // 1
arr16.indexOf(99); // -1
arr16.indexOf(1,1); // 4
arr16.indexOf(1,-3); // 4
arr16.indexOf(2,-1); // -1
arr16.lastIndexOf(2); // 3
arr16.lastIndexOf(2,-2); // 3
arr16.lastIndexOf(2,-3); // 1

isArray

isArray 是构造器函数上的方法,而不是原型对象上的方法,因此必须写 Array.isArray()。

1
Array.isArray([]) // true

总结判断数组的几种方法:

1
2
3
4
var arr17 =[];
arr17 instanceof Array; // true
({}).toString.apply([]); // "[object Array]"
[].constructor === Array; // true