类Array对象中是否该直接使用Array的原型方法?

题目来自于掘金一位分享者的分享 , 我经实验认证写篇文章记之

var obj={
    '2' : 3,
    '3' : 4,
    'length' : 2,
    'splice' : Array.prototype.splice,
    'push'   : Array.prototype.push
}
obj.push(1);
obj.push(2);
console.log(obj);
复制代码

请在下方评论区输入你认为的答案吧! 然后在看后面的答案解析吧 。




























答案与解析 :

{ 
  '2': 1,
  '3': 2,
  length: 4,
  splice: [Function: splice],
  push: [Function: push] 
}
复制代码

我们其实知道,在JS的世界观中,一切皆对象,Array也是对象,所以像obj这样的类Array对象是可以转化为Array对象的,比如下面这个例子:

var obj = {
	'0' : 1,
	'1' : 2,
	'2' : 3,
	length : 3
}
//es5写法
var arr1 = [].slice.call(obj);
//es6写法
var arr2 = Array.from(obj);
console.log(arr1,arr2);
复制代码

结果是:

[ 1, 2, 3 ] [ 1, 2, 3 ]
复制代码

这时候arr1arr2都是已经转为了Array对象,这是我们按部就班的写obj对象时,一切看上去都很好,但是如果我们调皮一下,把obj改为:

var obj = {
	'1' : 2,
        '2' : 3,
        '3' : 4,
	length : 3
}
复制代码

结果就开始调皮了:

[ <1 empty item>, 2, 3 ] [ undefined, 2, 3 ]
复制代码

不管是<1 empty item>还是undefined ,我们可以看出,把类Array对象转为数组的时候,转换过程会根据length属性和元素下标值来生成转换后的数组中元素,超出length范围的下标对应元素会被删除,而在length范围内下标不存在的元素会被赋值为空或undefined。转换为数组对象后,一切行为就和数组行为一致了,也即Array原型上的方法都可以正常使用了。

那如果我们不转换obj为Array,而是直接让obj继承Array原型上的方法呢?这也就引出本篇博文的标题:类Array对象中是否该直接使用Array原型的方法?其实答案是明了的,正如我们答案所示的那样令人意外,在类Array对象中直接使用Array原型方法显然是容易出错的写法。那我们接下来讨论,为什么答案是如此的,要想知道为什么我们需要追根溯源,我找到了Array.prototype.push方法的源代码,如下:

function ArrayPush () {  
    var n = TO_UNIT32(this.length);  
    var m = %_ArgumentsLength();  
    for (var i = 0; i < m; i++) { // 逐个复制元素
        this[i + n ] = %_Arguments(i);
    }  
    this.length = n + m; // 修改数组的length
    return this.length;
}
复制代码

关键就在这句this[i + n ] = %_Arguments(i);n=this.lengthi表示第i个参数,也就是说,元素的添加是和length属性有关的,push的下一位是下标为length的元素位置,本题中length=2 ,自然push的两个值会覆盖掉下标为23的元素位置

觉得本文对你有帮助,可以关注我的微信公众号!感谢关注!

转载于:https://juejin.im/post/5cac99c9f265da03b917fa70

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值