资讯专栏INFORMATION COLUMN

分析Array.apply(null, { length: 20 })

snowell / 3463人阅读

摘要:背景在阅读教程时有这么段其中这个表达式有点让人费解。对象就是一个类数组对象,因为没有初始化下标,的值,所以获取,下标的值得到的都是。

背景

在阅读VueJS教程时有这么段demo code:

</>复制代码

  1. render: function (createElement) {
  2. return createElement("div",
  3. Array.apply(null, { length: 20 }).map(function () {
  4. return createElement("p", "hi")
  5. })
  6. )
  7. }

其中这个表达式Array.apply(null, { length: 20 })有点让人费解。第一感觉这个表达式就是为了创建一个长度为20的数组,但表达式Array(20)也可以实现这个功能啊,为啥非要写那么复杂呢?看来情况没那么简单。。。

表达式Array.apply(null, { length: 2 })的值

先温故下基础(为了方便验证将表达式改成Array.apply(null, { length: 2 }),即length的值改成2):

基础1: Array构造函数

直接调用Array函数跟new方式调用是等价的,即:

</>复制代码

  1. var a = Array(2); // 等价于var a = new Array(2);

表示:创建一个长度为2的数组,注意该数组的元素并没有被初始化,即:

</>复制代码

  1. console.log(0 in a); // false
  2. console.log(1 in a); // false, 因为数组下标01还未初始化
  3. console.log(a[0]); // undefined, 因为数组下标0还未初始化,访问不存在的属性返回undefined
基础2: apply函数

ES5开始apply函数的第二个参数除了可以是数组外,还可以是类数组对象(即包含length属性,且length属性值是个数字的对象)。对象{length: 2}就是一个类数组对象,因为没有初始化下标0,1的值,所以获取0,1下标的值得到的都是undefined。

</>复制代码

  1. console.log(a[0]); // undefined
  2. console.log(a[1]); // undefined
  3. // 可以转成真正的数组
  4. var a = Array.prototype.slice.call({length: 2});
  5. console.log(Array.isArray(a)) // true
再看表达式Array.apply(null, { length: 2})的值

温故了基础后再看表达式Array.apply(null, { length: 2 })他就等价于:

</>复制代码

  1. // 1 熟悉一点: {length: 2}作为Array.apply第二个参数等同于[undefined, undefined]作为Array.apply第二个参数
  2. Array.apply(null, [undefined, undefined]);
  3. // 2 再熟悉一点:apply方法的执行结果
  4. Array(undefined, undefined);
  5. // 3 再再熟悉一点:Array方法直接调用和new方式调用等价
  6. new Array(undefined, undefined);

这样就很容易知道该表达式的值是一个长度为2,且每个元素值都被初赋值为undefined的数组(注意此时不是数组元素没有初始化,而是初始化成undefined,这就是跟Array(2)的区别

为啥非要写那么复杂呢?

回到最初的问题:为啥非要写那么复杂呢?回答这个问题前还得温故下map方法(来自MDN描述):

</>复制代码

  1. It is not called for missing elements of the array (that is, indexes that have never been set, which have been deleted or which have never been assigned a value).

即map函数并不会遍历数组中没有初始化或者被delete的元素(有相同限制还有forEach, reduce方法)。OK,疑问到此终于真相大白了:写这么“复杂”就是为了实现:创建一个长度为20,且每个元素都被初始化的数组。这样map方法就可以循环20次了。

</>复制代码

  1. // 被初始化的数组
  2. Array.apply(null, {length: 20}).map(function(val, index){
  3. console.log(index); // 循环20次
  4. });
  5. // 未被初始化的数组
  6. Array(20).map(function(val, index){
  7. console.log(index); // 不会被执行
  8. });

其实这已经是实现该功能很简洁的写法了,不得不佩服vuejs文档作者的基础功力。

如果为了少写几个字的话还可以把该表达式修改成:

</>复制代码

  1. Array.apply(null, Array(20)); // 第二个参数用Array(20)代替{length: 20}

还可以使用ES6 API更直观表达意图:

</>复制代码

  1. // 方法1:
  2. Array.from({length: 20})
  3. // 方法2
  4. Array(20).fill(null)

其他

Array(2) 等价于[,,],不等价于[undefined, undefined]

参考

Apply函数

Array.prototype.map方法

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88845.html

相关文章

  • es6常用数组操作及技巧汇总

    摘要:检测数组或者检测对象的原型链是否指向构造函数的对象或者终极大招注意不可以用此方法检查常用方法合并多个数组,返回合并后的新数组,原数组没有变化。返回值是由被删除的元素组成的一个数组。 定义数组 const array = [1, 2, 3]; 或者 const array = new Array(); array[0] = 1; 建议尽量使用第一种形式定义数组,采用new的形式在大量的数...

    Noodles 评论0 收藏0
  • es6常用数组操作及技巧汇总

    摘要:检测数组或者检测对象的原型链是否指向构造函数的对象或者终极大招注意不可以用此方法检查常用方法合并多个数组,返回合并后的新数组,原数组没有变化。返回值是由被删除的元素组成的一个数组。 定义数组 const array = [1, 2, 3]; 或者 const array = new Array(); array[0] = 1; 建议尽量使用第一种形式定义数组,采用new的形式在大量的数...

    jk_v1 评论0 收藏0
  • 学习笔记: JS数组

    摘要:数组元素甚至可以是对象或其它数组。它执行的是浅拷贝,这意味着如果数组元素是对象,两个数组都指向相同的对象,对新数组中的对象修改,会在旧的数组的相同对象中反应出来。 JS中的数组是弱类型的,数组中可以含有不同类型的元素。数组元素甚至可以是对象或其它数组。JS引擎一般会优化数组,按索引访问数组常常比访问一般对象属性明显迅速。数组长度范围 from 0 to 4,294,967,295(2^...

    archieyang 评论0 收藏0
  • ES6 生成 range 数组和 random 数组

    摘要:作者原文章创建数组除了字面量和外,还可以通过创建,为数组的长度。生成了长度为的空数组,注意,和数组中元素赋值为是有区别的中查看空数组为,而赋值为的数组为。 作者 @zwhu原文章 @github 创建数组除了字面量和 new Array() 外,还可以通过 Array(n) 创建,n 为数组的长度。 Array(n) 生成了长度为 n 的空数组,注意,和数组中元素赋值为 undefin...

    NotFound 评论0 收藏0

发表评论

0条评论

snowell

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<