在国外的一篇博客文章上有下面一些题目,刚开始做的时候错了4个,虽然涉及的知识点不算非常多,但的确有很多细节方面平时需要多加注意的,现在记录下每个题目背后所需要的知识。
Quiz mainly focuses on knowledge of scoping, function expressions (and how they differ from function declarations), references, process of variable and function declaration, order of evaluation, and a couple more things like
delete
operator and object instantiation.
以下结果在 jsfiddle 以及Chrome上进行了测试。
首先,了解在 ECMAScript 5th edition[1]中说明的JavaScript的数据类型 ,其中简单类型包括 数字、字符串、布尔值(true 和 false)、null 值和 undefined 值。其他所有的值都是对象 Object (包括 Array Date RegExp Function 等)。
然后,知道typeof 方法的值及其所对应的返回结果:
1.
(function(){ return typeof arguments; })();
Answer: "object"
arguments 在JavaScript 中是对象的一个特殊属性,返回的是object类型。
2.
var f = function g(){ return 23; }; typeof g();
Answer: Error[2]
以表达式方式定义的函数,函数名称是可选的。
如果一个函数定义表达式包含函数名称,函数的局部作用域将会包含一个绑定到函数对象的名称;函数的名称将成为函数内部的一个局部变量,可在函数内进行调用以实现递归操作。
3.
(function(x){ delete x; return x; })(1);
Answer: 1
delete 运算符,是一元运算符,它用来删除对象属性或者数组元素,当删除属性或者删除数组元素时不仅仅是设置了一个undefined 的值;当删除一个属性时,这个属性将不再存在,读取一个不存在的属性将返回undefined,但是可以通过 in 运算符来检测这个属性是否在对象中存在。
Notice: delete 希望它的操作数是一个左值,如果它不是左值,那么delete 将不进行任何操作同时返回true。否则,delete 将试图删除这个指定的左值。如果删除成功,delete 将返回true. 然而并不是所有的属性都可删除,一些内置核心和客户端属性是不能删除的,用户通过var 语句声明的变量是不能删除的,通过function 语句定义的函数和函数参数也不能删除。
左值: 表达式只能出现在赋值运算符的左侧。在JavaScript中,变量、对象属性和数组元素均是左值。ECMAScript规范允许内置函数返回一个左值,但自定义的函数则不能返回左值。
4.
var y = 1, x = y = typeof x; x;
Answer: "undefined"
x = y = typeof x 等价于 x = (y = (typeof x)) , 运算顺序从右至左
5.
(function f(f){ return typeof f(); })(function(){ return 1; });
Answer: "number"
这道题目做错了,后面在浏览器和JSHint下测试了会也不得其解,求助同学后终于想通了···+_-
这里的函数名与函数的形参名称一样,在JSHint下会提示 "f" is already defined , 在Chrome中没有报错,最后返回的是“number”。
因为当函数名与形参一致的时候 return typeof f(); 中的 f 是形参f 不是 函数名f(为什么?),所以f() 就相当于 (function(){ return 1;})() 。
而当形参与函数名f 不一致,但函数中仍然是return typeof f() 的时候,JSHint 没有提示错误,执行后浏览器最后会报错:Uncaught RangeError: Maximum call stack size exceeded 。
以后在写函数的时候要注意 函数名与形参 的命名。
6.
var foo = { bar: function() { return this.baz; }, baz: 1 }; (function(){ return typeof arguments[0](); })(foo.bar);
Answer: "undefined"
7.
var foo = { bar: function(){ return this.baz; }, baz: 1 } typeof (f = foo.bar)();
Answer: "undefined"
这两题有相似的地方,第六题按我的理解是把实参 foo.bar 赋值给了 arguments[0], 第七题则是赋值给 f;
重新赋值后变量中的 this 指向的都是全局对象,调用方法属于全局调用,因此返回的类型都是“undefined”
8.
var f = (function f(){ return "1"; }, function g(){ return 2; })(); typeof f;
Answer:
逗号运算符:首先计算左操作数,然后计算右操作数,最后返回右操作数的值。
9.
var x = 1; if (function f(){}) { x += typeof f; } x;
Answer: "1undefined"
函数定义返回的是一个新的Function对象,在if 语句里返回的是true;这里的函数f 的作用范围仅在if 语句的条件判断 if() 内,typeof f 中的f 仍然是undefined 。
备注:函数声明语句通常出现在JavaScript代码的最顶层,也可以嵌套在其他函数体内。但在嵌套时,函数声明只能出现在所嵌套函数的顶部。也就是说,函数定义不能出现在if 语句、while循环或其他任何语句中,正是由于函数声明位置的这种限制, ECMAScript标准规范并没有将函数声明归类为真正的语句。 像这种将函数声明放在其他语句内的做法并不具备可移植性。
10.
var x = [typeof x, typeof y][1]; typeof typeof x;
Answer: "string"
这里x 是一个数组的第二个元素,等价于 typeof y ,即:"undefined" , typeof x 即:"string"
如果 题目是 var x = [typeof x , typeof y][2]; 的话,x 则是undefined , typeof x 为"undefined"
11.
(function(foo){ return typeof foo.bar; })({ foo: { bar: 1 } });
Answer: "undefined"
返回值中的foo即是形参中的foo, 所以最后返回相当于 typeof {foo: {bar: 1}}.bar 。
12.
(function f(){ function f(){ return 1; } return f(); function f(){ return 2; } })();
Answer: 2
这里最外面的函数内定义了两个函数,不论return 的位置在哪里,都会先执行函数定义语句(定义式函数被提前),因此这个例子中的同名函数前一个函数总是会被后一个函数所覆盖。
13.
function f(){ return f; } new f() instanceof f;
Answer: false
这里 function f(){...}中的 return f 导致了 结果为false 。(WHY?)
instanceof 运算符希望左操作数是一个对象,右操作数标识对象的类。如果左侧的对象是右侧对象的实例,则表达式返回true;否则返回false。
14.
with (function(x, undefined){}) length;
Answer: 2 ( 没用到过with -_-||)
原网站给出的正确结果为 2 , 但在JSHint 下提示错误,Chrome下亦没有出现结果(求解)。
[1]: quiz的作者是基于3rd edition的,我是看的5th edition, 在quiz中没发现有什么问题。
[2]: "Error" in answer indicates that overall snippet results in a runtime error .
参考资料: JavaScript权威指南、ECMAScript 5th Edition、JavaScript Pattern、JavaScript: The Good Parts