您的位置:首页 > 其它

关于函数声明表达式的一道题目

2010-11-02 22:13 411 查看
f = function() { return true; };

g = function() { return false; };

( function() {

if (g() && [] == ![]) {

f = function f() { return false; };

function g() { return true; };

}

})();

f(); // What's the result?

答案在最下边:

f = function() { return true; }; // 1

g = function() { return false; }; // 2

(function() { // F

// A

if (g() && [] == ![]) {

f = function f() { return false; }; // 3

function g() { return true; }; // 4

}

})();

f(); // What's the result?

IE 6,7,8 会让函数声明体 3(错误地) 和 4(正确地) 在 A 处生效,于是 F 中,f 和 g 都是局部的了。这样,外界的 f 根本没有被赋值,结果是 true。等价的代码是:

f = function() { return true; }; // 1

g = function() { return false; }; // 2

(function() { // F

var f, g; // A

f = function(){ return false };

g = function(){ return true };

if (g() && [] == ![]) {

f = function () { return false; }; // 3

// function g() { return true; }; // 4

}

})();

f(); // What's the result?

Firefox 则是因为支持条件函数定义(1),在 A 处 3 和 4 都没有生效,导致 if 分支不成立,同样没有给外界 f 赋值,得到 true。精确描述它的行为很难,下面是一个等效的代码:

f = function() { return true; }; // 1

g = function() { return false; }; // 2

(function() { // F

var g1; // A

g1 = g;

if (g() && [] == ![]) {

g1 = function () { return true; };

f = function () { return false; }; // 3

// function g() { return true; }; // 4

}

})();

f(); // What's the result?

Chrome、Safari、IE9 beta 则依照了 ECMA 之规范,只有声明 4 在 A 处生效,等效代码是:

f = function() { return true; }; // 1

g = function() { return false; }; // 2

(function() { // F

var g = function () { return true; }; // A

if (g() && [] == ![]) {

f = function () { return false; }; // 3

// function g() { return true; }; // 4

}

})();

f(); // What's the result?

结果得到 false。

lifesinger说我分析的不深入,好,我将代码加了钩子后捕获各种浏览器的输出,加钩子的代码是:

var trace = function(m, x){console.log(m + ': ' + x); return x};

f = function() { return true; }; // 1

g = function() { return false; }; // 2

trace('[1f] now f', f);

trace('[1g] now g', g);

(function() { // F

trace('[2f] now f', f);

trace('[2g] now g', g);

if (trace('g() && [] == ![]', trace('g()',g()) && trace('[] == ![]', [] == trace('![]', ![])))) {

trace('[3f] now f', f);

trace('[3g] now g', g);

f = function f() { return 0; }; // 3

function g() { return 1; } // 4

trace('[4f] now f', f);

trace('[4g] now g', g);

}

trace('[5f] now f', f);

trace('[5g] now g', g);

})();

trace('[6f] now f', f);

trace('[6g] now g', g);

f()

chorme 6、Safari 5 的输出结果是:

[1f] now f: function () { return true; }

[1g] now g: function () { return false; }

[2f] now f: function () { return true; }

[2g] now g: function g() { return 1; }

g(): true

![]: false

[] == ![]: true

g() && [] == ![]: true

[3f] now f: function () { return true; }

[3g] now g: function g() { return 1; }

[4f] now f: function f() { return 0; }

[4g] now g: function g() { return 1; }

[5f] now f: function f() { return 0; }

[5g] now g: function g() { return 1; }

[6f] now f: function f() { return 0; }

[6g] now g: function () { return false; }

false

可以注意 [2f] 和 [2g] 的输出,chrome 6 遵守了 ECMA 的规定,忽略 3 处的函数声明,启用了 4 处的声明。所以你可以看到 [2g] 的里面是一个 1。而 f 则是直到 [4f] 才赋值为 function f(){return 0}。

Firefox 3.6.8 的输出结果是:

[1f] now f: function () { return true; }

[1g] now g: function () { return false; }

[2f] now f: function () { return true; }

[2g] now g: function () { return false; }

g(): false

g() && [] == ![]: false

[5f] now f: function () { return true; }

[5g] now g: function () { return false; }

[6f] now f: function () { return true; }

[6g] now g: function () { return false; }

true

可以看出少了好几行,这是因为 if 的短路所致。因为我们把 function g() 给弄进了 if 里,所以 [2g] 处的结果仍然是外界的 g。

IE 6,7,8 的输出是:

日志: [1f] now f: function() { return true; }

日志: [1g] now g: function() { return false; }

日志: [2f] now f: function f() { return 0; }

日志: [2g] now g: function g() { return 1; }

日志: g(): true

日志: ![]: false

日志: [] == ![]: true

日志: g() && [] == ![]: true

日志: [3f] now f: function f() { return 0; }

日志: [3g] now g: function g() { return 1; }

日志: [4f] now f: function f() { return 0; }

日志: [4g] now g: function g() { return 1; }

日志: [5f] now f: function f() { return 0; }

日志: [5g] now g: function g() { return 1; }

日志: [6f] now f: function() { return true; }

日志: [6g] now g: function() { return false; }

true

IE 6,7,8 错误地启用了 3 处的声明,把 F 里定义了一个局部变量 f,所以 [2f] 处得到了不同的结果。因为 f 已经成为 F 的局部变量,因此外界的 f 没有收到影响。

IE9 的输出是:

日志: [1f] now f: function() { return true; }

日志: [1g] now g: function() { return false; }

日志: [2f] now f: function() { return true; }

日志: [2g] now g: function g() { return 1; }

日志: g(): true

日志: ![]: false

日志: [] == ![]: true

日志: g() && [] == ![]: true

日志: [3f] now f: function() { return true; }

日志: [3g] now g: function g() { return 1; }

日志: [4f] now f: function f() { return 0; }

日志: [4g] now g: function g() { return 1; }

日志: [5f] now f: function f() { return 0; }

日志: [5g] now g: function g() { return 1; }

日志: [6f] now f: function f() { return 0; }

日志: [6g] now g: function() { return false; }

false

和 chrome 6 的结果只有空格位置的区别。

根据运算符的优先级:先计算[] == ![] 然后在计算g() && 和前边的结果;

至于 [] == ![] 的问题,因为 ![] 等于 false,是个简单值,所以需要把 [] 转换为简单值(toString)。而 [].toString() 的结果是空字符串,所以在 == 的宽松比较下它们相等。

本人测试结果:

* IE 6,7,8: true
* Firefox 3.6.8: true
* Chrome 6, IE9 beta, Safari 5: false

转自:http://lifesinger.org/blog/category/dev/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: