Array.prototype.push()源码探究
在学习阮⼀峰⽼师的《ES6⼊门》的数组的扩展运算符时遇到了这样⼀串代码
// ES5的写法
var arr1 =[0,1,2];
var arr2 =[3,4,5];
Array.prototype.push.apply(arr1, arr2);
// ES6 的写法
let arr1 =[0,1,2];
let arr2 =[3,4,5];
arr1.push(...arr2);
上⾯列出了合并两种数组的⽅法,第⼆种由于⽤了ES6扩展运算符,显得更加的简单和⽅便,但是对于传统JS⽅法却产⽣了疑惑,下⾯来探究⼀下。
JS的函数有⼀个特别重要的属性:arguments。
有时候我们要对arguments进⾏处理,但是 arguments 只是⼀个类数组,只有 length 属性,没有什么 push() , pop() 等⽅法,这时我们常常会使⽤到 Array 的那些原形⽅法和 call 以及 apply 来对arguments来进⾏处理。
例如:
切掉第⼀个元素: Array.shift.call( arguments )
添加⼀个元素: Array.push.call( arguments,numbers )
function ac(){
var ray =[]
Array.prototype.push.call( arguments,1)
console.log(arguments)//Arguments [1, callee: ƒ, Symbol(Symbol.iterator): ƒ]
}
明明arguments就不是数组,为什么数组的⽅法可以作⽤在它⾝上⽽不会产⽣错误呢?
来看看V8引擎中 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;
js合并两个数组}
从源码可以看出,push操作其实只是简单的复制元素。只要⼀个对象具有下⾯的两个特性,就可以使⽤Array.prototype.push():
1. 可读写的length属性
2. 对象本⾝可以存取属性
来⼀个例⼦
var obj ={};
[].push.call(obj,'a');
console.log(obj);// { '0': 'a', length: 1 }
可以看到,对象中不仅多了键值对’0’: ‘a’,,还多了键值对length: 1。
从源码还可以得到另外⼀个信息:push⽅法复制元素使⽤的是指针(this),所以可以很清楚的了解到push是浅复制。
再看下⼀个例⼦
var array=[];
var item={};
for(var i=0;i<5;i++){
item.a=i;
array.push(item);
}
console.log(array);
//[ { a: 4 }, { a: 4 }, { a: 4 }, { a: 4 }, { a: 4 } ]
为什么它会输出⼀样的值呢?很简单,因为push为浅复制,所以导致了这种情况发⽣。
浅复制就是指,复制的是地址,⽽不是值本⾝,若是地址中的值改变,那么复制的值也会随之改变

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。