(function() { var a = b = 5; })(); console.log(b); //5
这个问题的陷阱就是,在当即执行函数表达式(IIFE
)中,有两个赋值,可是其中变量a使用关键词var来声明。这就意味着a是这个函数的局部变量。与此相反,b被分配给了全局做用域(译注:也就是全局变量)。javascript
这个问题另外一个陷阱就是,在函数中没有使用”严格模式” ('use strict'
)。若是 严格模式开启,那么代码就会报错 ” Uncaught ReferenceError: b is not defined
” 。请记住,若是这是预期的行为,严格模式要求你显式地引用全局做用域。因此,你须要像下面这么写:java
(function() { 'use strict'; var a = window.b = 5; })(); console.log(b);
答案:
5node
在 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; }
这个问题测试了开发人员对 javascript 中继承及原型(prototype)属性的知识。这也验证了开发人员是否有能力扩展原生数据类型功能(虽然不该该这么作)。闭包
在这里,另外一个关键点是,看你怎样避免重写可能已经定义了的方法。这能够经过在定义本身的方法以前,检测方法是否已经存在。app
String.prototype.repeatify = String.prototype.repeatify || function(times) {/* code here */};
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();
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
,在本例中即为第一行代码设置的。
修复前一个问题,让最后一个console.log() 打印输出Aurelio De Rosa.
答案:
这个问题能够经过运用call()
或者apply()
方法强制转换上下文环境。若是你不了解这两个方法及它们的区别,我建议你看看这篇文章 function.call
和function.apply
之间有和区别。 下面的代码中,我用了call()
,但apply()
也能产生一样的结果:
console.log(test.call(obj.prop));
var nodes = document.getElementsByTagName('button'); for (var i = 0; i < nodes.length; i++) { nodes[i].addEventListener('click', function() { console.log('You clicked element #' + i); }); }
请问,若是用户点击第一个和第四个按钮的时候,控制台分别打印的结果是什么?为何?
答案:
概念:闭包(Closures)。对于每个JavaScript开发者来讲,若是你想在网页中编写5行以上的代码,那么准确理解和恰当使用闭包是很是重要的。若是你想开始学习或者只是想简单地温习一下闭包,那么我强烈建议你去阅读 Colin Ihrig 这个教程:JavaScript Closures Demystified
也就是说,代码打印两次You clicked element
#NODES_LENGTH
,其中NODES_LENGTH
是nodes
的结点个数。缘由是在for循环完成后,变量i的值等于节点列表的长度。此外,由于i在代码添加处理程序的做用域中,该变量属于处理程序的闭包
。你会记得,闭包中的变量的值不是静态的,所以i的值不是添加处理程序时的值(对于列表来讲,第一个按钮为0,对于第二个按钮为1,依此类推)。在处理程序将被执行的时候,在控制台上将打印变量i的当前值,等于节点列表的长度。
修复上题的问题,使得点击第一个按钮时输出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)); }
写一个isPrime()函数,当其为质数时返回true,不然返回false。
答案:
我认为这是面试中最多见的问题之一。然而,尽管这个问题常常出现而且也很简单,可是从被面试人提供的答案中能很好地看出被面试人的数学和算法水平。
首先, 由于JavaScript不一样于C或者Java,所以你不能信任传递来的数据类型。若是面试官没有明确地告诉你,你应该询问他是否须要作输入检查,仍是不进行检查直接写函数。严格上说,应该对函数的输入进行检查。
第二点要记住:负数不是质数。一样的,1和0也不是,所以,首先测试这些数字。此外,2是质数中惟一的偶数。没有必要用一个循环来验证4,6,8。再则,若是一个数字不能被2整除,那么它不能被4,6,8等整除。所以,你的循环必须跳过这些数字。若是你测试输入偶数,你的算法将慢2倍(你测试双倍数字)。能够采起其余一些更明智的优化手段,我这里采用的是适用于大多数状况的。例如,若是一个数字不能被5整除,它也不会被5的倍数整除。因此,没有必要检测10,15,20等等。若是你深刻了解这个问题的解决方案,我建议你去看相关的Wikipedia介绍。
最后一点,你不须要检查比输入数字的开方还要大的数字。我感受人们会遗漏掉这一点,而且也不会由于此而得到消极的反馈。可是,展现出这一方面的知识会给你额外加分。
如今你具有了这个问题的背景知识,下面是总结以上全部考虑的解决方案:
function isPrime(number) { // If your browser doesn't support the method Number.isInteger of ECMAScript 6, // you can implement your own pretty easily if (typeof number !== 'number' || !Number.isInteger(number)) { // Alternatively you can throw an error. return false; } if (number < 2) { return false; } if (number === 2) { return true; } else if (number % 2 === 0) { return false; } var squareRoot = Math.sqrt(number); for(var i = 3; i <= squareRoot; i += 2) { if (number % i === 0) { return false; } } return true; }