我们几乎每天都要用到push方法,我们真的明白在调用push方法后,浏览是怎么运行这个方法?
其中ecma规范第三版(1999)是这样定义的:
- 1 调用对象的[Get]方法获取参数列表中第一个参数长度
- 2 将结果用ToUint32方法赋值给n
- 3 在参数列表中获取下一个参数,如果没有,直接跳到第七步
- 4 调用对象的[Put]方法将当前参数Tostring,put到当前对象中去
- 5 n自增1
- 6 回到第三步,循环
- 7 调用对象的[Put]方法,将参数长度和n put 到当前对象中去
- 8 返回n
push原生方法的长度属性为1
到了2011年,我们push规范进行了变更,大致变更如下:
- 1 调用ToObject处理this对象,将结果赋值给O
- 2 调用O对象的内部方法[Get]将第一个参数长度赋值给lenVal
- 3 将ToUint32(lenVal)赋值给n
- 4 将传递给函数调用的参数从左到右,依次赋值给items
- 5 如果items不为空,重复下列方法: a.移除items中的第一个元素,并且将移除元素的值赋给E b.调用O对象的[Put]内部方法,在O对象上设置ToString(n),E和true属性。 c.n自增1
- 6 当items为空时,调用O对象的[Put]内部方法,设置O对象的参数长度,n和true等属性。
- 7 返回n
NOTE: push方法被刻意设计为一种通用的方法;它并不要求this对象是一个数组对象。因此它能使用特定方法被其他对象调用。
var obj={
addElem : function addElem(elem){
[].push.call(this,elem);
//Array.prototype.push.call(this,elem);
}
}
obj.addElem('1');
obj.addElem('2');
console.log(obj.length) //result is 2
时光回到2015年,ecma规范又一次更新,push当然也是更新了
我们来看看具体有哪些更新:
- 1 ToObject(this)并且将值赋给O
- 2 调用ReturnIfAbrupt(O) ps:这个函数是啥意思?目前还没弄懂,弄懂再回来补充
- 3 将O的长度调用ToLength()赋值给len ps:这个toLength又是什么呢?
- 4 调用ReturnIfAbrupt(len)
- 5 步骤还是跟第五版一样,将所有传递进函数的参数从左至右赋值给items。
- 6 将items中的元素个数赋值给argCount
- 7 如果len + argCount > 2的53次方减一,抛出TypeError exception
- 8 如果items不为空,重复下列行为: a.从items移除第一个元素,并且将这个元素的值赋给E b.调用Set方法设置O对象的ToString(len),E和true属性 c.ReturnIfAbrupt(setStatus) d.len自增1
- 9 如果items为空,调用Set方法,设置O对象"length",len和true属性
- 10 ReturnIfAbrupt(setStatus).
- 11 返回len
es6内部抽象程度更高,更加规范,调用了很多方法来处理不同的过程,那让我们来了解研究这些方法到底是干什么的。
ToObject
Object抽象方法它可以将参数转变为对象类型的值。
| arguments type | result |
|---|---|
| Completion Record | If argument is an abrupt completion, return argument. Otherwise return ToObject(argument.[[value]]). |
| Undefined | Throw a TypeError exception. |
| Null | Throw a TypeError exception. |
| Boolean | 返回新的Boolean对象 |
| Number | 返回新的Number对象 |
| String | 返回新的String对象 |
| Symbol | 返回新的Symbol对象 |
| Object | 返回对象 |
其中Boolean,Number,String,Symbol,参数类型为这些时,返回的新对象都是用internal slot(暂且翻译为内部插槽重新设置的对象),但是何为internal slot,还不理解,理解再来叙说。
ReturnIfAbrupt
完成时 类型被用作记录运行时,值传递的状态,例如一些跳出局部控制的状态(break, continue, return and throw)。
| Field | Value | Meaning |
|---|---|---|
| [[type]] | One of normal, break, continue, return, or throw | 其中某一种状态已经被调用 |
| [[value]] | Undefined, Null, Boolean, String, Symbol, Number, and Object中的一种,或者empty | 值已经产生 |
| [[target]] | any ECMAScript string or empty | The target label for directed control transfers. |
重点:abrupt completion(突然完成) 是指在[[Type]]之中除了nomral之外的状态