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

近期进击掘金,感觉是个很好的平台,以前自己怎么都不知道呢?闲话不多说,这篇博文分享一个JavaScript中的小问题 ,题目来自于掘金一位分享者的分享,先预告一下博主水平有限也做错了

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的元素位置

觉得本文对你有帮助,可以关注我的微信公众号!感谢关注!
在这里插入图片描述

发布了65 篇原创文章 · 获赞 58 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/AngelLover2017/article/details/89161839