Have a look on Array in Javascript.

看看 Javascript 的引用类型之 Array 的认识及如何对其操作

Posted by mslinzz on 2017-03-01

前言

除 Object 之外, Array 类型恐怕是 ECMAScript 中最常用的类型了. 而且, ECMAScript中的数组与其它多语言中的数组有着相当打的区别. 虽然 ECMAScript 数组与其它语言中的数组都是数据的有序列表, 但与其他语言不同的是, ECMAScript 数组的每一项可以保存任何类型的数据. 也就是说, 可以用数组的第一个位置来保存字符串, 用第二个位置来保存数值, 用第三个位置来保存对象, 以此类推. 而且, ECMAScript 数组的大小是可以动态调整的, 即可以随着数据的添加自动增长以容纳新增数据.

创建数组的不同方式

第一种使用 Array 的构造函数:

1
2
3
4
5
6
7
8
9
var colors = new Array();
// OR
var colors = new Array(20);
// OR
var colors = new Array('white');
// OR
var colors = Array(3);
// OR
var colors = Array('white');

第二种是使用数组字面量表示法:

1
2
3
var colors = ['white', 'black', 'purple'];
// OR
var colors = [];

注意:请不要在最后一个元素后面加 , 用以隔开前后元素, 如下案例:

1
2
3
var colors = ['white', 'black', 'purple',]; // 不要这样做! 这样会导致创建一个'undefined'的值, 相应的数组长度也会 + 1
// OR
var colors = [, , ,]; // 更不要这样!

获取数组的长度

1
2
var colors = ['white', 'black', 'purple'];
var len = colors.length;

检测是数组. 常常被问到的一个面试题

1
2
3
4
5
6
7
8
function isArrayFn(val) {
// 先判断是否支持 ES5 提供的 Array.isArray
if (typeof Array.isArray === 'function') {
return Array.isArray(val);
} else {
return Object.prototype.toString.call(val) === '[object Array]';
}
}

以上代码为最优解决方法 ~

扩展1: typeof 可判断 - Function, String, Number, Boolean, Undefined
扩展2: 也可用 arr instanceof Array 判断是否是数组
扩展3: 也可用 arr.constructor === Array 判断是否是数组

数组之 - 转化方法

简单的转换方式:

1
2
3
4
5
var colors = ['white', 'black', 'purple'];
console.log(colors.toString()); // white,black,purple
console.log(colors.toLocaleString()); // white,black,purple
console.log(colors.valueOf()); // ["white", "black", "purple"]
console.log(colors); // ["white", "black", "purple"]

不同分隔符转换方式, 符号可自定义:

1
2
3
var colors = ['white', 'black', 'purple'];
console.log(colors.join(',')); // 以 `,` 隔开 // white,black,purple
console.log(colors.join('||')); // 以 `||` 隔开 // white||black||purple

数组之 - 栈方法

栈的特点是 LIFO (Last-In-First-Out) 后进先出的数据结构, 也就是后添加的项最早被移除.

模拟栈的方式, 插入(即推入), 移除(即弹出), 只发生在一个位置 —— 栈的顶部.

ECMAScript 为数组模拟栈的方式提供了 push()pop().

1
2
3
4
5
6
var colors = ['white', 'black'];
colors.push('purple'); // 添加一项
console.log(colors); // ["white", "black", "purple"]
var item = colors.pop(); // 推出最后一项, 并取得推出的项
console.log(item); // "purple"

数组之 - 队列方法

队列的特点是 FIFO (First-In-First-Out) 先进先出的数据结构, 即在队列的列表末尾添加项, 从列表的前端移除项.

模拟队列的方式, ECMAScript 为数组移除列表前端提供了 shift() 的方法.

1
2
3
4
5
6
var colors = ['white', 'black'];
colors.push('purple'); // 添加一项
console.log(colors); // ["white", "black", "purple"]
var item = colors.shift(); // 推出最后一项, 并取得推出的项
console.log(item); // "white"

另外, ECMAScript 还为数组提供了与 shift() 相反的 unshift(), unshift() 能在数组前端添加任意项并返回新数组的长度. 因此, 同时使用 unshift()pop() 可以从相反的方向来模拟队列, 即在数组的前端添加项, 从数组的末端移除项, 如下:

1
2
3
4
5
6
var colors = ['white', 'black'];
colors.unshift('blue'); // 在前端推入一项
console.log(colors); // ["blue", ""white", "black"]
var item = colors.pop(); // 推出最后一项, 并取得推出的项
console.log(item); // "black"

数组之 - 重排序方法

数组已经存在两个可以直接用来重排序的方法, 即 reverse()sort()

1
2
3
4
var num = [6, 3, 7, 2, 9];
console.log(num.reverse()); // [9, 2, 7, 3, 6]
console.log(num.sort()); // [2, 3, 6, 7, 9]

reverse() 反转数组. sort() 对数组升序排序. 但是以上两个都不够灵活, 如下案例:

1
2
var num = [6, 5, 15, 2, 9];
console.log(num.sort()); // [15, 2, 5, 6, 9]

sort() 重排序后, 15 换在 其他各位数的前面, 因为 sort() 会把各项先转换成 toString() 然后在进行比较, 显然 "15" 的字符串位于其他个位的字符串, 所以直接用 sort() 比较是有缺陷的, 但是好的一点是, sort() 可以接收一个比较函数最为参数, 所以我们可以对 sort() 进行扩展, 如下代码:

1
2
3
4
5
6
7
8
9
function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}

compare() 函数接收两个参数, 如果第一个参数应该位于第二个参数之前则返回 -1, 如果两个参数相等, 则返回 0, 如果第一个参数应该位于第二个参数之后则返回 1. 使用此方法比较如下:

1
2
3
var num = [6, 5, 15, 2, 9];
num.sort(compare);
console.log(num.sort()); // [2, 5, 6, 9, 15]

这个比较函数适用于大多数的数据类型, 只要将其函数做为参数传递给 sort() 即可.

另外, 上述 compare() 的扩展是升序排序, 当然也可以进行降序排序. 如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
function compare(value1, value2) {
if (value1 < value2) {
return 1;
} else if (value1 > value2) {
return -1;
} else {
return 0;
}
}
var num = [6, 5, 15, 2, 9];
num.sort(compare);
console.log(num.sort()); // [15, 9, 6, 5, 2]

数组之 - 操作方法

ECMAScript 为操作已经包含在数组中项提供了很多方法.

concat() 方法可以基于当前数组创建一个新数组, 不会影响原数组. 直接看代码:

1
2
3
4
5
6
var colors = ['white', 'black', 'purple'];
var colors2 = colors.concat(); // colors2 为 colors 的一个副本
console.log(color2); // ["white", "black", "purple"]
var colors3 = colors.concat('yellow', ['blue', 'orange']);
console.log(color3); // ["white", "black", "purple", "yellow", "blue", "orange"]

slice() 方法能够基于当前数组中的一个或多个项创建一个新数组, 不会影响原数组. 直接看代码:

1
2
3
4
5
6
var colors = ['white', 'black', 'purple', 'blue', 'green'];
var colors2 = colors.slice(1); // 只传一个参数时, 从该参数指定的起始位置到数组的末尾所有项
console.log(colors2); // ["black", "purple", "blue", "green"]
var colors3 = colors.slice(1, 3); // 传两个个参数时, 从该参数指定的起始位置到第二个参数指定位置 - 1 的中间所有项, 即不包括第二个参数指定结束位置的项
console.log(colors3); // ["black", "purple"]

splice() 方法可谓是最强大的, 它是向数组的中部插入项, 也可删除项的同时插入长度不等的集合, 主要用途有: 删除, 插入, 替换. 注意的是, 该方法会影响原数组.

1
2
3
4
5
6
7
8
9
10
11
12
var colors = ['white', 'black', 'purple'];
var removed = colors.splice(0, 1); // 删除第一项
console.log(colors); // ["black", "purple"]
console.log(removed); // ["white"]
removed = colors.splice(1, 0, 'yellow', 'orange'); // 从 1 的位置插入两项
console.log(colors); // ["black", "yellow", "orange", "purple"]
console.log(removed); // []
removed = colors.splice(1, 1, 'red', 'green'); // 从 1 的位置插入两项, 删除一项
console.log(colors); // ["black", "red", "green", "orange", "purple"]
console.log(removed); // ["yellow"]

数组之 - 位置方法

ECMAScript5 为数组实例添加了两个位置方法: indexOf() 和 `lastIndexOf(), 可用于查找特定项在数组中的位置, 该两个方法都有两个参数, 第一个参数为要查找的项, 第二个参数为可选参数, 表示查找起点位置的索引.

1
2
3
4
5
6
7
8
9
10
11
var num = [6, 5, 15, 2, 9];
console.log(num.indexOf(5)); // 1
console.log(num.indexOf(20)); // -1
console.log(num.indexOf(2)); // 3
console.log(num.lastIndexOf(15)); // 2
console.log(num.indexOf(3, 3)); // -1, 查找 3 从索引 3 的位置开始, 没有找到, 返回 -1
console.log(num.indexOf(9, 3)); // 4, 查找 4 从索引 3 的位置开始, 可以找到
console.log(num.lastIndexOf(5, 3)); // 1
1
2
3
4
5
6
var person = {name: 'awesome'};
var people = [{name: 'awesome'}];
var morePeople = [person];
console.log(people.indexOf(person)); // -1
console.log(morePeople.indexOf(person)); // 0

支持以上两个方法的浏览器包括 IE 9+, Firefox 2+, Safari 3+, Opera 9.5+, Chrome

数组之 - 迭代方法

ECMAScript5 为数组定义了 5 个迭代方法, 每个方法都接收两个参数, 第一个参数为要在每一项上运行的函数, 第二个参数为可选项表示运行该函数的作用域对象 —— 影响 this 的值. 传入这些方法中的函数会接收三个参数, 分别是: 数组项的值, 该项在数组中的位置和数组对象本身. 但是他们相对应的返回值不同, 首先下面是这 5 个迭代方法:

  • every() - 如果该函数对每一项都返回 true, 则返回 true
  • filter() - 返回该函数会返回 true 的项组成的数组
  • forEach() - 没有返回值, 相当于循环
  • map() - 返回每次函数调用的结果组成的数组
  • some() - 如果该函数对任一项返回 true, 则返回 true

以上方法都不会修改数组中的包含的值, 请看代码演示:

1
2
3
4
5
6
7
var num = [6, 5, 15, 2, 9];
var everyRes = num.every(function(item, index, array) {
return (item > 2);
})
console.log(everyRes); // false
1
2
3
4
5
6
7
var num = [6, 5, 15, 2, 9];
var someRes = num.some(function(item, index, array) {
return (item > 2);
})
console.log(someRes); // true
1
2
3
4
5
6
7
var num = [6, 5, 15, 2, 9];
var filterRes = num.filter(function(item, index, array) {
return (item > 2);
})
console.log(filterRes); // [6, 5, 15, 9]
1
2
3
4
5
6
7
var num = [6, 5, 15, 2, 9];
var mapRes = num.map(function(item, index, array) {
return (item * 2);
})
console.log(mapRes); // [12, 10, 30, 4, 18]
1
2
3
4
5
6
var num = [6, 5, 15, 2, 9];
num.forEach(function(item, index, array) {
// 执行某些操作
console.log(item);
})

支持这些迭代方法的浏览器包括 IE 9+, Firefox 2+, Safari 3+, Opera 9.5+, Chrome

数组之 - 归并方法

ECMAScript5 还新增了两个归并数组的方法, reduce()reduceRight(). 这两个方法都会迭代数组的所有项, 然后构建一个最终返回值.

reduce() 从数组的第一项开始(即 0 项), 逐个向后遍历
reduceRight() 从数组的最后一项开始(即 length - 1 项), 逐个向前遍历

以上两个方法, 接收两个参数, 第一个参数是每项上调用的函数, 第二个参数可选表示做为归并基础的初始值. 该函数方法有 4 个参数, 分别是: 前一个值, 当前值, 项的索引和数组对象本身. 其中特点就是, 当前值会做为下个执行函数的第一个参数, 请看代码:

1
2
3
4
5
6
7
var num = [6, 5, 15, 2, 9];
var sum = num.reduce(function(prev, cur, index, array) {
return prev + cur;
})
console.log(sum); // 37 从前到后
1
2
3
4
5
6
7
var num = [6, 5, 15, 2, 9];
var sum = num.reduceRight(function(prev, cur, index, array) {
return prev + cur;
})
console.log(sum); // 37 从后到前

两个执行结果是一样的, 但是执行顺序不一样, 因为现在是用于比较基础的逻辑运算.

支持这两个归并函数的的浏览器包括 IE 9+, Firefox 3+, Safari 4+, Opera 10.5+, Chrome

总结

以上出自 << JavaScript 高级程序设计(第3版) >> 对于引用类型 Array 的总结摘录. 供个人温故知新.