首页 > 代码库 > 一道 JavaScript 面试题
一道 JavaScript 面试题
有一道 JavaScript 面试题。
f = function () { return true; };g = function () { return false; };(function() { if (g() && [] == ![]) { f = function () { return false; }; function g() { return true; } }})();console.info(f());
首先看前两行
var f = function () { return true; };var g = function () { return false; };
这两行定义了两个变量,而不是函数定义,变量是可以重新赋值的。
第四行就比较有趣了
(function () { if (g() && [] == ![]) { f = function () { return false; }; function g() { return true; } }})();
在 if 条件中调用了函数 g(),但是,这个 g 是第二行定义的函数 g 吗?答案是否定的,因为在匿名函数中又定义了函数 g,局部的定义覆盖了外部的定义,所以,这里调用的是内部函数 g,返回为 true。第一个条件通过,进入第二个条件。
其实,最有趣的是第二个条件 [] == ![] 。
先看 ![] ,在 JavaScript 中,当用于布尔运算的时候,比如在这里,对象的非空引用被视为 true,空引用 null 则被视为 false。由于这里不是一个 null, 而是一个没有元素的数组,所以 [] 被视为 true, 而 ![] 的结果就是 false 了,如果你在 Visual Studio 的编辑器中输入,就会直接看到提示,表达式永远为假。
当一个布尔值参与到条件运算的时候,true 会被看作 1, 而 false 会被看作 0,见这里的说明: Javascript 中的相等与不等
现在条件变成了 [] == 0 的问题了,当一个对象参与条件比较的时候,它会被求值,求值的结果是数组成为一个字符串,[] 的结果就是 ‘‘ ,而 ‘‘ 会被当作 0 ,所以,条件成立。
条件内的代码如下:
f = function () { return false; };function g() { return true; }
注意 f 的前面没有 var ,所以,不是局部变量,因此,这里会通过闭包访问到外部的变量 f, 重新赋值,现在执行 f 函数返回值已经成为 false 了。
至于 g 则不会有这个问题,这里是一个函数内定义的 g,不会影响到外部的 g 函数。
最后一行的结果自然也就出来了,就是 false。