10分钟了解JavaScript特殊对象Array-Like Objects
沉沙 2018-07-23 来源 : 阅读 978 评论 0

摘要:本篇JavaScript教程探讨了JavaScript特殊对象Array-Like Objects,希望阅读本篇文章以后大家有所收获,帮助大家对JavaScript的理解更加深入。

Array-Like

JavaScript 中一切皆为对象,那么什么是 Array-Like Objects?顾名思义,就是像数组的对象,当然,数组本身就是对象嘛!稍微有点基础的同学,一定知道 arguments 就是 Array-Like Objects 的一种,能像数组一样用 [] 去访问 arguments 的元素,有 length 属性,但是却不能用一些数组的方法,如 push,pop,等等。

那么,什么样的元素是 Array-Like Objects?我们来看看 underscore 中对其的定义。

var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;

var getLength = property('length');

var isArrayLike = function(collection) {

  var length = getLength(collection);

  return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;

};

   

很简单,不是数组,但是有 length 属性,且属性值为非负 Number 类型即可。至于 length 属性的值,underscore 给出了一个上限值 MAX_ARRAY_INDEX,其实是 MAX_SAFE_INTEGER(感谢 @HangYang 同学指出) ,因为这是 JavaScript 中能精确表示的最大数字。

想想还有什么同时能满足以上条件的?NodeList,HTML Collections,仔细想想,甚至还有字符串,或者拥有 length 属性的对象,函数(length 属性值为形参数量),等等。

Array-Like to Array

有的时候,需要将 Array-Like Objects 转为 Array 类型,使之能用数组的一些方法,一个非常简单粗暴并且兼容性良好的方法是新建个数组,然后循环存入数据。

我们以 arguments 为例。

function fn() {

  // Uncaught TypeError: arguments.push is not a function

  // arguments.push(4);

 

  var arr = [];

  for (var i = 0, len = arguments.length; i < len; i++)

    arr[i] = arguments[i];

 

  arr.push(4); // [1, 2, 3, 4]

}

 

fn(1, 2, 3);

   

但是这不是最优雅的,更优雅的解法大家一定都知道了,use Array.prototype.slice(IE9- 会有问题)。

function fn() {

  var arr = Array.prototype.slice.call(arguments);

  arr.push(4); // arr -> [1, 2, 3, 4]

}

 

fn(1, 2, 3);

   

或者可以用 [] 代替 Array.prototype 节省几个字节。

function fn() {

  var arr = [].slice.call(arguments);

  arr.push(4); // arr -> [1, 2, 3, 4]

}

 

fn(1, 2, 3);

   

如果非得追求性能,用 [] 会新建个数组,性能肯定不及前者,但是由于引擎的优化,这点差异基本可以忽略不计了(所以很多框架用的就是后者)。

为什么这样可以转换?我们简单了解下,主要的原因是 slice 方法只需要参数有 length 属性即可。首先,slice 方法得到的结果是一个 新的数组,通过 Array.prototype.slice.call 传入的参数(假设为 a),如果没有 length 属性,或者 length 属性值不是 Number 类型,或者为负,那么直接返回一个空数组,否则返回 a[0]-a[length-1] 组成的数组。(具体可以看下 v8 源码 https://github.com/v8/v8/blob/master/src/js/array.js#L621-L660)

当然,ES6 提供了更简便的方法。

var str = "helloworld";

var arr = Array.from(str); 

// ["h", "e", "l", "l", "o", "w", "o", "r", "l", "d"]

   

小结下,如果要把 Array-Like Objects 转为 Array,首选 Array.prototype.slice,但是由于 IE 下 Array.prototype.slice.call(nodes) 会抛出错误(because a DOM NodeList is not a JavaScript object),所以兼容的写法如下。(但还有一点要注意的是,如果是 arguments 转为 Array,最好别用 Array.prototype.slice,V8 下会很慢,具体可以看下 避免修改和传递 arguments 给其他方法 — 影响优化 )

function nodeListToArray(nodes){

  var arr, length;

 

  try {

    // works in every browser except IE

    arr = [].slice.call(nodes);

    return arr;

  } catch(err){

    // slower, but works in IE

    arr = [];

    length = nodes.length;

 

    for(var i = 0; i < length; i++){

       arr.push(nodes[i]);

     }  

 

    return arr;

  }

   

Others

很多时候,某个方法你以为接收的参数是数组,其实类数组也是可以的。

Function.prototype.apply() 函数接收的第二个参数,其实也可以是类数组。

var obj = {0: 4, length: 2};

var arr = [1, 2, 3];

Array.prototype.push.apply(arr, obj);

console.log(arr); // [1, 2, 3, 4, undefined]  


本文由职坐标整理发布,学习更多的JavaScript相关知识,请关注职坐标WEB前端JavaScript频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程