前言
不知道你有没有看见过这样一段代码,
// 如何不使用循环创建一个长度为100的数组的Object.keys()方法
var arr = Object.keys(Array.apply(null, {length:100})).map(function(item){
return +item;
});
console.log(arr);
提示:+号是一个string转换number格式的小技巧,你也可以使用parseInt。
// 或者在vue.js教程中也出现过这样一个DOM
render: function (createElement) {
return createElement('div',
Array.apply(null, { length: 20 }).map(function () {
return createElement('p', 'hi')
})
)
}
这两个例子的都出现过Array.apply(null, {length:100})这段代码,咋一看这是个啥?为什么Array创建数组可以这样?{length:100}是什么鬼?别着急等我慢慢讲来。
解析第一步
- 其实直接调用Array和new Array()两种方式创建数组是一样的,即:
var a = [1,2];
var b = Array(2);
var c = new Array(2);
console.log(a); //[ 1, 2 ]
console.log(b); //[ <2 empty items> ]
console.log(c); //[ <2 empty items> ]
注意此处输出的是[ <2 empty items> ],是因为b,c数组虽然被创建,但是该数组的元素并没有被初始化。
console.log(b[0]); // undefined
console.log(c[0]); // undefined
因为数组下标0还未初始化,访问不存在的属性返回undefined
解析第二步
apply(),的第二个参数不光可以是数组还可以是个类数组对象(即包含length属性,且length属性值是个数字的对象),所有其实{length:2}也是一个类数组对象,只是没有进行初始化而已,取值的话返回undefined。
Array.apply({length:2})===Array.apply([undefined, undefined])
解析第三步
map()函数并不会遍历数组中没有初始化或者被delete的元素(有相同限制还有forEach, reduce方法),so这里也差不多解释了为什么不直接new Array(2)或Array(2),而是要这样创建一个长度为2的空数组Array.apply({length:2})。
// 被初始化的数组
Array.apply(null, {length: 2}).map(function(val, index){
console.log(index); // 0 1
});
// 未被初始化的数组
Array(2).map(function(val, index){
console.log(index); // 不会被执行
});
总结
再次之前你需要了解三个知识点:
1.Array和new Array()创建数组是没有被初始化的。
2.apply()的第二个参数可以是个类数组对象。
3.map()函数并不会遍历数组中没有初始化的元素。
拓展
如果你还是觉得Array.apply(null, {length:100})有点长的话,看过来。
// 方法1:Array(20)代替{length: 20}
Array.apply(null, Array(20));
// 方法2:使用ES6,from()函数
Array.from({length: 20})
// 方法3: 使用ES6,fill()函数
Array(20).fill(undefined)