第七章 数组的扩展
Array.from()
将类数组对象(比如arguments
对象和DOM操作返回的NodeList
集合)和可遍历对象(iterable, 比如Map
和Set
)
let a = {
0: 1,
1:100,
length: 2
}
[].slice.call(a);
Array.from(a)
也可以将字符串转换成数组(因为字符串部署了Iterator接口):
Array.from('baidu')
// ["b", "a", "i", "d", "u"]
对于数组,此方法返回一个新数组
类数组对象,关键点在于具有length属性
Array.from()
的第二个参数是一个遍历方法,类似map方法,将处理后的元素放回原数组
let a = {
0:100,
1:200,
length:2
}
Array.from(a, (value) =>(value *2)); //[200, 400]
Array.from()
的第三个参数是用于绑定第二个参数中使用的this
let a = {
0: 100,
1: 200,
length: 2
};
let b = Array.from(a, () = > (this.value * 2), {value: 200});
console.log(b); // [NaN, NaN]
let c = Array.from(a, function() {
return this.value * 2
}, {
value: 200
});
console.log(c); // [400, 400]
b
的值之所以是NaN
,因为箭头函数的this
取决于绑定时的对象, 绑定时this
指向window
用法之一:快速填充数组:
let array = {length:10};
Array.from(array, () => ('value'))
// ["value", "value", "value", "value", "value", "value", "value", "value", "value", "value"]
扩展运算符...
将数组变为参数序列
let a = [1, 2, 3];
let b = [4, 5, 6];
Array.prototype.push.apply(a, b);
a.push(...b)
可以代替apply
方法
let a = [1, 2, 3];
console.log(Math.max.apply(null, a));
console.log(Math.max(...a))
可以将扩展运算符与解构赋值结合使用,比如复制数组时:
let a = [1,2,3];
let b = [...a];
// 也可以利用解构赋值
let [...b] = a;
如果将扩展运算符用于数组赋值,只能放在参数的最后一位,否则会报错。
也可以用于将字符串转变为数组:
let s = 'hello';
let b = Array.from(s);
let c = [...s]
任何 Iterator 接口的对象(比如arguments
对象,Map
、Set
),都可以用扩展运算符转为真正的数组。
将arguments转换为数组:
function test(a, b) {
console.log([...arguments]);
console.log([].slice.apply(arguments));
console.log(Array.prototype.slice.call(arguments))
}
test(1, 2)
转换Set
和Map
对象
let a = new Set([1, 2, 3, 4, 5]);
let b = [...a]
对于那些没有部署 Iterator 接口的类似数组的对象,扩展运算符就无法将其转为真正的数组。
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let b = [...arrayLike]; // Uncaught TypeError: arrayLike is not iterable
let c = Array.from(arrayLike); // ['a', 'b', 'c']
let d = Array.prototype.slice.call(arrayLike); // ['a', 'b', 'c']
Generator函数也可以使用扩展运算符
const go = function * () {
yield 1;
yield 2;
yield 3;
};
console.log([...go()]); //[1,2,3]
Array.of()
Array()
构造函数的不足在于,接受参数的个数不同,导致行为差异:
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
Array.of
基本上可以用来替代Array()
或new Array()
, Array.of
总是返回参数值组成的数组
Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]
数组实例的copyWithin()
方法
let a = [1, 2, 3, 4, 5, 6];
a.copyWithin(1, 3, 5)
- 参数一:从哪个位置开始被替换
- 参数二:从哪个位置开始复制内容(含)
- 参数三:复制内容到哪个位置结束(不含)
数组实例的find()
和findIndex()
let a = [
{id: 1, value: 10},
{id: 2, value: -2},
{id: 3, value: -3},
{id: 4, value: 5},
{id: 5, value: -5},
];
console.log(a.find((value) => (value.value < 0))); // {id: 2, value: -2}
console.log(a.findIndex((value) => (value.value < 0))) // 1
find
没找到,返回undefined
,findIndex
没找到返回-1
这两个方法都可以接受第二个参数,用来绑定回调函数的this
对象。
let b = a.find(function(value) {
return value.value < this.value
}, {value: 5})
indexOf
方法无法识别数组的NaN
成员,但是findIndex
方法可以借助Object.is
方法做到。
[1,2,NaN].findIndex((val) => (Object.is(val, NaN)))
数组实例的fill()
用来填充数组
[].fill(a, b, c)
- a:被填充内容
- b:填充起始位置(含)
- c:填充结束位置 (不含)
Array.of(5, 5, 5).fill(7, 0, 2);
// [7, 7, 5]
数组实例的keys()
、values()
、entries()
注意,返回的不是一个数组,而是一个遍历器对象, 这个遍历器对象可以使用for...of
遍历,也可以手动调用遍历器对象的next
方法,进行遍历。
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
数组实例的includes()
方法
用来判断数组是否有这一项,和indexOf
不同的是:
indexOf
要与-1
比较,而includes
返回的是布尔值indexOf
使用===
比较,而NaN !== NaN
,所以出现误判,而includes
不会
[NaN].indexOf(NaN); //-1
[NaN].includes(NaN); //true
空位
数组的空位就是没有赋值的位置,和undefined
是不同的
由于空位的处理规则非常不统一,所以建议避免出现空位。