ES3和ES5中函数调用(function call) 的浏览器实现差异.

正美今天扔出来的类似下面的代码:

参考代码:

var o = {
    test: function () {alert('origin')}
};
o.test(o.test = function(){ alert('changed'); });

  

这段代码,我们直觉,觉得打印 origin 才是合理的.  至少我个人是这样认为的.

但是.Chrome17-, IE8- 都会打印changed .  而 Firefox0.8+,Safai3+, Opera9.2+,IE9+ 则都打印origin.  

 

出现这个问题的根源,我们通过翻看 ES3和ES5,可以找到原因.  原来ES3和ES5,在此处是有冲突的. 道格拉斯认为ES3是不合理的. 所以更改了这里的逻辑.

ES3:

Function Calls
The production CallExpression : MemberExpression Arguments is evaluated as follows:
1. Evaluate MemberExpression.
2. Evaluate Arguments, producing an internal list of argument values (see 11.2.4).
3. Call GetValue(Result(1)).

 

ES5:

11.2.3 Function Calls
The production CallExpression : MemberExpression Arguments is evaluated as follows:

1. Let ref be the result of evaluating MemberExpression.
2. Let func be GetValue(ref).
3. Let argList be the result of evaluating Arguments, producing an internal list of argument values (see 11.2.4).

 

可见ES5 对MemberExpression 也就是这里的函数名部分的表达式所获取的引用,进行getValue运算是早于 对实参列表进行evalute的.

而ES3则恰恰相反.  

 

那么我们从纵观历史的角度来看问题. 孰对孰错呢?

.Firefox4才开始真正的按照ES5标准来实现引擎.那么Firefox 3.6-的浏览器,就并没有遵守当时的ES3现行标准.

.Opera11.6开始比较完善的按照ES5实现.所以Opera11.5-的浏览器.同FF3.6-一样.并没有遵守ES3. 

.Safari3-5 也是如此.在Safari5.11仍然对ES5支持度十分底下的前提下,居然始终不曾遵守过ES3.

.Chrome 从5开始部分支持ES5的API,并在版本11开始,比较完善的按照ES5实现. 但是一直到版本17.居然仍然是按照ES3的实现. 很明显是不对的.

 

那么对这里 从历史角度来看,最好的居然是IE系列.  IE系从9开始按照ES5实现jscript引擎。结果其表现在这一点上就十分完美.  IE8-按照ES3实现.IE9+ 按ES5实现.

 

这一次,IE值得表扬!奖小红花一朵 。

 

 


 

最后说说ES3的这处奇怪的设定.

对于new NewExpression

就完全没有这个问题.也与ES5是一致的.

即 先 evalute newExpression,然后对其getValue, 然后才去 evalute Arguments

参考代码:

var cons = function () {this.name = 1;};
var obj = new cons(cons = function () {this.name = 2;});
alert(obj.name)

所有浏览器的实现都不会有差异,因为ES3,5之间没有差异.那为什么function call 会这样奇怪呢? 我暂时还想不出当初这样设计的理由.....先记一下吧.

 

 

posted @ 2011-12-02 11:34  Franky  阅读(3535)  评论(9编辑  收藏  举报