layout: post
title: JS 中的 Array 对象
tag: 前端开发
今天, 让我们和 JS 的 Array 对象来个了解吧...
构造函数
Array 是 JS 的原生对象, 同时也是一个构造函数, 意味着你可以通过它生成新的数组. 如:
const arr = new Array(2);
然而, 我们强烈反对你这样做 !
因为 Array 构造函数有一个很大的缺陷, 不同的参数会导致它的行为不一致:
参数为 空时, 返回一个空数组;
参数为 单个正整数, 返回一个定长的数组;
参数为 非正整数的数值, 会报错;
参数为 非数值 (如字符串 / 布尔值 / 对象等), 返回以该参数为成员的新数组;
参数为 多个时, 返回以所有参数为成员的新数组.
我们推荐你直接使用数组字面量的形式生成新的数组.
静态方法
Array.isArray()
我们知道 typeof 运算符在遇到引用类型的时候就无能为力了. 如何解决 ?
- const arr = [1, 2, 3];
- typeof arr; // 'object'
- Array.isArray(arr); // true
通过上面这段代码, 我想你已经知道方法了.
实例方法
valueOf(), toString()
valueOf 方法和 toString 方法都是 Object 对象的通用方法, 允许被重写. Array 对象就这么做了!
- const arr = [1, 2, 3];
- arr.valueOf(); // [1, 2, 3], 返回数组本身
- arr.toString(); // '1,2,3', 返回数组的字符串形式
那些曾经让人头痛的实例方法
相信不少人都曾经吃过不少 Array 实例方法的苦,
到底 有哪些方法 ?
到底 哪些方法会改变原数组 ?
到底 这些方法怎么用 ?
到底 这些方法的参数是什么 ?
到底 这些方法的返回值是什么 ?
Okay, 我们来解决它们吧 !
会改变原数组的实例方法
- push(), pop(), shift(), unshift()
- const arr = [];
- arr.push(1); // 1
- arr.push('a'); // 2
- arr.push(true, {}); // 4
- arr; // [1, 'a', true, {}], 原数组改变了
你看, 通过上面这段代码, 我们能看到什么 ?
push(),
作用: 在数组的末端添加一个或多个元素
参数: 要添加的元素 (数值 / 字符串 / 布尔型或对象等)
返回: 添加新元素后的数组长度
有添加了, 要有删除才可以平衡嘛 ! 于是,
- const arr = ['a', 'b', 'c'];
- arr.pop(); // 'c', 返回删除的元素
- arr; // ['a', 'b'], 原数组改变了
- [].pop(); // undefined
- pop(),
作用: 用于删除数组的最后一个元素
参数: 空
返回: 删除的最后一个元素
末端那些事儿解决了, 如果要在头部操作呢 ?
- const arr = ['a', 'b', 'c'];
- arr.shift(); // 'a'
- arr; // ['b', 'c'], 原数组改变了
- shift(),
作用: 用于删除数组的第一个元素
参数: 空
返回: 删除的第一个元素
shift 有'卸载'的意思, so, 你就不会把 shift/ unshift 搞混了.
- const arr = ['c', 'd'];
- arr.unshift('a', 'b'); // 4
- arr; // ['a', 'b', 'c', 'd'], 原数组改变了
- unshift(),
作用: 在数组的第一个位置添加元素 (一个或多个)
参数: 要添加的元素
返回: 添加新元素后的数组长度
- reverse(), sort(), splice()
- const arr = ['a', 'b', 'c'];
- arr.reverse(); // ['c', 'b', 'a']
- arr; // ['c', 'b', 'a'], 原数组改变了
- reverse(),
作用: 逆转排列数组元素
参数: 空
返回: 逆转排列的新数组
- const arr = [1, 3, 2, 4, 101, 11];
- arr.sort(); // [1, 101, 11, 2, 3, 4]
- arr; // [1, 101, 11, 2, 3, 4], 原数组改变了
通过上面这段代码, 可以发现, sort 方法不是按照大小排序, 而是按照字典顺序排序. 通常意义上的从小到大的排序方式怎么实现呢 ? sort 方法允许我们传入一个函数作为参数, so, 在函数中你可以制定规则了.
- const arr = [1, 3, 2, 4, 101, 11];
- arr.sort(
- function(a, b) { // 参数函数本身接受两个参数, 表示进行比较的两个数组成员
- return a - b; // 返回值大于 0, 表示第一个成员大, 要排在第二个成员后面
- }
- ); // [1, 2, 3, 4, 11, 101]
- sort(),
作用: 对数组元素进行排序, 默认按照字典顺序
参数: 空 / 自定义排序规则的函数
返回: 排序之后的新数组
splice 方法功能很强大哦. 我们通过它的用法很容易可以看出, 如下:
arr.splice(start, conunt, [addElement1], [addElement2], ...);
参数:
start: 删除的起始位置 (从 0 开始, 为负代表从倒数位置开始删除)
count: 要被删除的元素个数 (等于 0 时表示不删除, 只插入)
addElement1: 可选参数, 表示要被插入数组的新元素
- const arr = ['a', 'b', 'c', 'd', 'e', 'f'];
- arr.splice(4, 2, 1, 2); // ['e', 'f'], 返回删除的元素
- arr; // ['a', 'b', 'c', 'd', '1', '2'], 原数组改变了
- splice(),
作用: 删除原数组的一部分成员, 并可以再删除位置添加新的数组成员
参数: 起始位置, 删除个数, [待插入元素...]
返回: 删除的元素组成的数组
不改变原数组的实例方法
- join(), concat(), slice()
- const arr = [1, 2, 3, null, 4,,5];
- arr.join('-'); // 1-2-3--4--5
- // 数组成员为 undefined, null 或空位时, 会被转成空字符串
- // 通过 `call` 方法, join() 也可用于字符串和类似数组的对象, 如下
- Array.prototype.join.call('hello', '-'); // 'h-e-l-l-o'
- const obj = {0: 'a', 1: 'b', length: 2};
- Array.prototype.join.call(obj, '-'); // 'a-b'
- join(),
作用: 指定参数作为分隔符, 将所有数组成员连接为一个字符串返回
参数: 不提供参数时, 默认用逗号分隔
返回: 指定分隔符分隔之后的字符串
- const arr = ['hello'];
- arr.concat(['world'], {a: 1, b: 2}, 6, '!');
- // ['hello', 'world', {a:1, b: 2}, 6, '!']
- arr; // ['hello'], 原数组没有改变哦
- concat(),
作用: 用于多个数组的合并, 讲过新数组的成员, 添加到原数组之后
参数: 数组, 也接受其他类型的值
返回: 合并后的新数组
如果数组成员包括对象, concat 方法返回当前数组的一个浅拷贝. 我们通过一个例子来看一下'浅拷贝'是什么 ?
- const obj = {a: 1};
- const orgArr = [obj]; // 原数组包含一个对象
- const newArr = orgArr.concat();
- // 现在我们改变原数组包含的对象 obj
- obj.a = 2;
- newArr[0].a; // 2
- // 可以看到我们修改 obj.a, 新数组也跟着改变, 因为拷贝的是引用地址, 反之亦如此
slice 方法, 用法:
- arr.slice(start, end);
- const arr = ['a', 'b', 'c'];
- arr.slice(0); // ['a', 'b', 'c']
- arr.slice(1); // ['b', 'c']
- arr.slice(1, 2); // ['b']
- arr.slice(); // ['a', 'b', 'c'], 原数组的拷贝
- arr.slice(-2); // ['b', 'c']
- arr.slice(-2, -1); // ['b']
- arr; // ['a', 'b', 'c'], 原数组没有改变
- Array.prototype.slice.call(arguments);
- // `slice` 方法的一个重要应用, 就是类似数组的对象转为真正的数组.
- // `join` 方法时, 也如此用过.
- slice(),
作用: 用于提取目标数组的一部分
参数: 起始位置 (从 0 开始), 终止位置 (不包括该位置本身, 省略时表示一直到原数组末尾);
参数为空, 等于返回一个原数组的拷贝
参数为负, 找寻位置时按倒数查询
如果 start>= end, 返回空数组
返回: 返回提取部分组成的新数组, 原数组不变
- map(), forEach(), filter(), some(), every()
- function fn(elem, index, arr) { ... };
- arr.map/forEach/filter/some/every(fn, [可选参数])
参数函数中参数的解释:
elem: 当前成员
index: 当前位置
arr: 数组本身
- const arr = ['1', '2'];
- const arra = ['a', 'b', 'c'];
- arr.map(function(elem, index, arr) {
- return elem * index; // [0, 2]
- });
- arr.map(function(elem) {
- return this[elem];
- }, arra); // ['b', 'c']
- map(),
作用: 将数组的所有成员依次传入参数函数, 把每一次的执行结果组成一个新数组返回
参数: 接受一个函数作为参数; 第二个参数可选, 用来绑定回调函数内部的 this 变量
返回: 每一次执行结果组成的新数组
注意: map 方法, 会跳过数组的空位, 不会跳过 undefined 和 null
forEach 方法和 map 方法的异同:
相同: 用法一致, 参数是一个函数 (接受三个参数), 可以接受第二参数绑定函数内部的 this
不同: forEach 方法不返回值, 只用来操作数据
结论: 若数组遍历的目的是为了得到返回值, 用 map 方法, 否则用 forEach 方法
注意: forEach 方法无法中断执行, 总是会将所有成员遍历完, 如果要按条件中断遍历, 去使用 for 循环
- const arr = [1, 2, 3];
- const out = [];
- arr.forEach(function(elem) {
- this.push(elem * elem);
- }, out);
- out; // [1, 4, 9]
filter 方法和 map 方法的异同:
相同: 用法一致, 参数是一个函数 (接受三个参数), 可以接受第二参数绑定函数内部的 this
不同: forEach 方法返回 结果 true 的成员组成的一个新数组
- [1, 2, 3, 4, 5].filter(function (elem, index, arr) {
- return index % 2 === 0;
- });
- // [1, 3, 5]
some, every 方法和 map 方法的异同:
相同: 用法一致, 参数是一个函数 (接受三个参数), 可以接受第二参数绑定函数内部的 this
不同: some, every 方法返回 一个布尔值, 表示判断数组成员是否符合某种条件
some 方法, 只要一个成员的返回值为 true, 整个方法返回值就是 true
every 方法, 要所有成员的返回值为 true, 整个方法返回值才是 true
对于空数组, some 方法返回 false, every 方法返回 true, 回调函数都不会执行
reduce(), reduceRight()
reduce 方法和 reduceRight 方法, 依次处理数组的每个成员, 最终累计为一个值. 除了起始方向不同, 其他完全一样.
- const arr = [1, 2, 3, 4, 5];
- arr.reduce(function(a, b) {
- console.log(a, b);
- return a + b; // 15
- })
- // 1 2
- // 3 3
- // 6 4
- // 10 5
- // 最后结果: 15
reduce 方法第一个参数为函数, 该函数的接受四个参数解释:
累计变量, 必须, 默认为数组的第一个成员
当前变量, 必须, 默认为数组的第二个成员
当前位置 (从 0 开始), 可选
原数组, 可选
reduce(),
作用: 依次处理数组的每个成员, 返回累计值
参数: 接受一个函数作为参数; 第二参数可选但很重要, 用来对累计变量指定初值
返回: 累计值
我们来看看第二参数的在处理空数组时的一个用处吧.
- function add(prev, cur) {
- return prev + cur;
- }
- [].reduce(add);
- // TypeError: Reduce of empty array with no initial value
- // 类型错误: 空数组的 reduce 方法没有初值
- [].reduce(add, 1); // 1
- indexOf(), lastIndexOf()
- indexOf(),
作用: 返回给定元素在数组中第一次出现的位置
参数: 指定元素; 可以接受第二参数, 表示搜索的开始位置
返回: 第一次出现的位置, 若没出现, 则返回 -1
lastIndexOf(),
作用: 返回给定元素在数组中最后一次出现的位置
参数: 指定元素
返回: 最后一次出现的位置, 若没出现, 则返回 -1
来源: http://www.jianshu.com/p/9717379de192