问题1: 作用域(Scope)
考虑以下代码:
(function() { var a = b = 5; })(); console.log(b);
控制台(console)会打印出什么?
答案:5
如果 严格模式开启,那么代码就会报错 ” Uncaught ReferenceError: b is not defined” 。请记住,如果这是预期的行为,严格模式要求你显式地引用全局作用域。所以,你需要像下面这么写:
(function() { 'use strict'; var a = window.b = 5; })(); console.log(b);
问题2: 创建 “原生(native)” 方法
在 String 对象上定义一个 repeatify 函数。这个函数接受一个整数参数,来明确字符串需要重复几次。这个函数要求字符串重复指定的次数。举个例子:
console.log('hello'.repeatify(3));
应该打印出hellohellohello.
答案:
String.prototype.repeatify = String.prototype.repeatify || function(times) { var str = ''; for (var i = 0; i < times; i++) { str += this; } return str; };
在这里,另一个关键点是,看你怎样避免重写可能已经定义了的方法。这可以通过在定义自己的方法之前,检测方法是否已经存在。
String.prototype.repeatify = String.prototype.repeatify || function(times) {/* code here */};
问题3: 变量提升(Hoisting)
执行以下代码的结果是什么?为什么?
function test() { console.log(a); console.log(foo()); var a = 1; function foo() { return 2; } } test();
答案:
这段代码的执行结果是undefined 和 2。
这个结果的原因是,变量和函数都被提升(hoisted) 到了函数体的顶部。因此,当打印变量a时,它虽存在于函数体(因为a已经被声明),但仍然是undefined。换言之,上面的代码等同于下面的代码:
function test() { var a; function foo() { return 2; } console.log(a); console.log(foo()); a = 1; } test();
问题4: 在javascript中,`this`是如何工作的
以下代码的结果是什么?请解释你的答案。
var fullname = 'John Doe'; var obj = { fullname: 'Colin Ihrig', prop: { fullname: 'Aurelio De Rosa', getFullname: function() { return this.fullname; } } }; console.log(obj.prop.getFullname()); var test = obj.prop.getFullname; console.log(test());
答案:
这段代码打印结果是:Aurelio De Rosa 和 John Doe 。原因是,JavaScript中关键字this所引用的是函数上下文,取决于函数是如何调用的,而不是怎么被定义的。
在第一个console.log(),getFullname()是作为obj.prop对象的函数被调用。因此,当前的上下文指代后者,并且函数返回这个对象的fullname属性。相反,当getFullname()被赋值给test变量时,当前的上下文是全局对象window,这是因为test被隐式地作为全局对象的属性。基于这一点,函数返回window的fullname,在本例中即为第一行代码设置的。
问题5: call() 和 apply()
修复前一个问题,让最后一个console.log() 打印输出Aurelio De Rosa.
答案:
这个问题可以通过运用call()或者apply()方法强制转换上下文环境。
console.log(test.call(obj.prop));
问题6: 闭包(Closures)
考虑下面的代码:
var nodes = document.getElementsByTagName('button'); for (var i = 0; i < nodes.length; i++) { nodes[i].addEventListener('click', function() { console.log('You clicked element #' + i); }); }
请问,如果用户点击第一个和第四个按钮的时候,控制台分别打印的结果是什么?为什么?
答案:
两次打印都是nodes.length的值。
问题7: 闭包(Closures)
修复上题的问题,使得点击第一个按钮时输出0,点击第二个按钮时输出1,依此类推。
答案:
有多种办法可以解决这个问题,下面主要使用两种方法解决这个问题。
第一个解决方案使用立即执行函数表达式(IIFE)再创建一个闭包,从而得到所期望的i的值。实现此方法的代码如下:
var nodes = document.getElementsByTagName('button'); for (var i = 0; i < nodes.length; i++) { nodes[i].addEventListener('click', (function(i) { return function() { console.log('You clicked element #' + i); } })(i)); }
另一个解决方案不使用IIFE,而是将函数移到循环的外面。这种方法由下面的代码实现:
function handlerWrapper(i) { return function() { console.log('You clicked element #' + i); } } var nodes = document.getElementsByTagName('button'); for (var i = 0; i < nodes.length; i++) { nodes[i].addEventListener('click', handlerWrapper(i)); }
问题8:数据类型
考虑如下代码:
console.log(typeof null); console.log(typeof {}); console.log(typeof []); console.log(typeof undefined);
答案:
object object object undefined
问题9:事件循环
下面代码运行结果是什么?请解释。
function printing() { console.log(1); setTimeout(function() { console.log(2); }, 1000); setTimeout(function() { console.log(3); }, 0); console.log(4); } printing();
答案:
1 4 3 2