近期进击掘金,感觉是个很好的平台,以前自己怎么都不知道呢?闲话不多说,这篇博文分享一个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 ]
这时候arr1
和arr2
都是已经转为了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.length
,i
表示第i
个参数,也就是说,元素的添加是和length
属性有关的,push
的下一位是下标为length
的元素位置,本题中length=2
,自然push
的两个值会覆盖掉下标为2
和3
的元素位置
觉得本文对你有帮助,可以关注我的微信公众号!感谢关注!