【转】典型的JavaScript面试题
问题1: 作用域(Scope)
(function() {
var a = b = 5;
})();
console.log(b);
控制台(console)会打印出什么?
答案:
上述代码会打印出5
。
这个问题的陷阱就是,在立即执行函数表达式(IIFE)中,有两个赋值,但是其中变量a
使用关键词var
来声明。这就意味着a
是这个函数的局部变量。与此相反,b
被分配给了全局作用域(译注:也就是全局变量)。
这个问题另一个陷阱就是,在函数中没有使用”严格模式” ('use strict';
)。如果 严格模式开启,那么代码就会报错 ” Uncaught ReferenceError: b is not defined” 。请记住,如果这是预期的行为,严格模式要求你显式地引用全局作用域。所以,你需要像下面这么写:
(function () {
'use strict';
var a = b = 5;
}) ();
console.log(b);
自己注:严格模式下,火狐依然是输出5,而360浏览器才报错是” Uncaught ReferenceError: b is not defined”。
问题2: 变量提升(Hoisting)
执行以下代码的结果是什么?为什么?
function test() {
console.log(a);
console.log(foo()); var a = 1;
function foo() {
return 2;
}
} test();
答案:
这段代码的执行结果是undefined
和 2
。
这个结果的原因是,变量和函数都被提升到了函数体的顶部。因此,当打印变量a
时,它虽存在于函数体(因为a
已经被声明),但仍然是undefined
。换言之,上面的代码等同于下面的代码:
function test() {
function foo() {
return 2;
}
var a; console.log(a);
console.log(foo()); a = 1;
} test();
关于变量提升函数提升:
1、函数会首先被提升,然后才是变量。
2、变量提升,就是把变量提升提到函数的top的地方。只是提升变量的声明,并不会把赋值也提升上来。
3、函数提升是把整个函数都提到前面去。
4、解析器在向执行环境中加载数据时,解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。(JavaScript高级程序设计111页)。
变量的问题,莫过于声明和赋值两个步骤,而这两个步骤是分开的。
函数声明被提升时,声明和赋值两个步骤都会被提升,而普通变量却只能提升声明步骤,而不能提升赋值步骤。
变量被提升过后,先对提升上来的所有对象统一执行一遍声明步骤,然后再对变量执行一次赋值步骤。而执行赋值步骤时,会优先执行函数变量的赋值步骤,再执行普通变量的赋值步骤。
当你明白这三点后,一切都豁然开朗了。
问题3: 在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
,在本例中即为第一行代码设置的。
问题4: call() 和 apply()
修复前一个问题,让最后一个console.log()
打印输出Aurelio De Rosa
.
答案:
这个问题可以通过运用call()
或者apply()
方法强制转换上下文环境。关于这两个方法的区别 call() 和 apply()。 下面的代码中,我用了call()
,但apply()
也能产生同样的结果:
console.log(test.call(obj.prop));
问题5: 闭包(Closures)
考虑下面的代码:
var nodes = document.getElementsByTagName('button');
for (var i = ; i < nodes.length; i++) {
nodes[i].addEventListener('click', function () {
console.log('You clicked element #' + i);
});
}
请问,如果用户点击第一个和第四个按钮的时候,控制台分别打印的结果是什么?为什么?
答案:
无论点击哪个按钮都是打印出 You clicked element #4。
也就是说,代码打印两次You clicked element #NODES_LENGTH
,其中NODES_LENGTH
是nodes的结点个数。原因是在for循环完成后,变量i
的值等于节点列表的长度。此外,因为i
在代码添加处理程序的作用域中,该变量属于处理程序的闭包。你会记得,闭包中的变量的值不是静态的,因此i
的值不是添加处理程序时的值(对于列表来说,第一个按钮为0,对于第二个按钮为1,依此类推)。在处理程序将被执行的时候,在控制台上将打印变量i
的当前值,等于节点列表的长度。
一个重要的知识点:闭包只能取得包含函数中任何变量的最后一个值。
问题6: 闭包(Closures)
修复上题的问题,使得点击第一个按钮时输出0,点击第二个按钮时输出1,依此类推。
答案:
有多种办法可以解决这个问题,下面主要使用两种方法解决这个问题。
第一个解决方案使用立即执行函数表达式(IIFE)再创建一个闭包,从而得到所期望的i的值。实现此方法的代码如下:
var nodes = document.getElementsByTagName('button');
for (var i = ; i < nodes.length; i++) {
nodes[i].addEventListener('click', (function (i) {
return function () {
console.log('You clicked element #' + i);
}
}) (i));
};
另一个解决方案不使用IIFE,而是将函数移到循环的外面。这种方法由下面的代码实现:
var nodes = document.getElementsByTagName('button');
function handlerWrapper(i) {
return function () {
console.log('You clicked element #' + i);
}
}
for (var i = ; i < nodes.length; i++) {
nodes[i].addEventListener('click', handlerWrapper(i));
}
问题7:事件循环
下面代码运行结果是什么?请解释。
function printing() {
console.log(1);
setTimeout(function () {
console.log(2);
}, 1000);
setTimeout(function () {
console.log(3);
}, 0);
console.log(4);
}
printing();
答案:
输出结果:
想知道为什么输出顺序是这样的,你需要弄了解setTimeout()
做了什么,以及浏览器的事件循环原理。浏览器有一个事件循环用于检查事件队列,处理延迟的事件。UI事件(例如,点击,滚动等),Ajax回调,以及提供给setTimeout()
和setInterval()
的回调都会依次被事件循环处理。因此,当调用setTimeout()
函数时,即使延迟的时间被设置为0
,提供的回调也会被排队。回调会呆在队列中,直到指定的时间用完后,引擎开始执行动作(如果它在当前不执行其他的动作)。因此,即使setTimeout()
回调被延迟0
毫秒,它仍然会被排队,并且直到函数中其他非延迟的语句被执行完了之后,才会执行。
有了这些认识,理解输出结果为“1”就容易了,因为它是函数的第一句并且没有使用setTimeout()
函数来延迟。接着输出“4”,因为它是没有被延迟的数字,也没有进行排队。然后,剩下了“2”,“3”,两者都被排队,但是前者需要等待一秒,后者等待0秒(这意味着引擎完成前两个输出之后马上进行)。这就解释了为什么“3”在“2”之前。
原文链接:10道典型的JavaScript面试题
问题8:
以下 JavaScript 代码,在浏览器中运行的结果是
var foo ={n:1};
(function(foo){
console.log(foo.n);
foo.n = 3;
var foo = {n:2};
console.log(foo.n);
})(foo);
console.log(foo.n);
答案:依次输出 1 2 3
解析:
var foo={n:1}; //全局作用域下的foo变量,是一个对象,引用类型 //然后是一个立即执行的匿名函数,传入上面的foo,由于是引用类型
//所以匿名函数参数的foo即是对上面那个foo的引用
(function(foo){
console.log(foo.n);//这里的foo就是全局作用域下的foo,n为1,所以第一次打印出1
foo.n=3;//这里是设置全局作用域下的foo中n属性,将n变为3
var foo={n:2};//这里是在这个匿名函数作用域内新建的一个foo变量,由于作用域不同,不覆盖全局作用域下的foo变量
console.log(foo.n);//这里由于是在匿名函数作用域内,首选打印匿名函数作用域内的foo.n,也就是上面的2
})(foo); console.log(foo.n);//最后,由于匿名函数中改变了全局作用域中的foo.n为3,所以打印出3
【转】典型的JavaScript面试题的更多相关文章
- 五个典型的 JavaScript 面试题
阅读原文 在IT界,需要大量的 JavaScript 开发者.如果你的能力能够胜任这一角色,那么你将获得许多更换工作和提高薪水的机会.但是在你被公司录取之前,你需要展现你的技术实力,以便通过面试环节. ...
- 10道典型的JavaScript面试题
问题1: 作用域(Scope) 考虑以下代码: (function() { ; })(); console.log(b); 上述代码会打印出5.这个问题的陷阱就是,在立即执行函数表达式(IIFE)中, ...
- 5个典型的JavaScript面试题
在IT界,需要大量的 JavaScript 开发者.如果你的能力能够胜任这一角色,那么你将获得许多换工作和提高薪水的机会.但是在你被公司录取之前,你需要展现你的技术,以便通过面试环节.在这篇文章中,我 ...
- 五个典型的JavaScript面试题
问题1: 范围(Scope) 思考以下代码: 1 2 3 4 5 (function() { var a = b = 5; })(); console.log(b); 控制台(console ...
- 10个典型的JavaScript面试题
问题1:作用域 考虑如下代码: JavaScript 1 2 3 4 5 6 7 (function() { var a = b = 5; })(); console.log(b) ...
- 互联网中级Javascript面试题
互联网中级Javascript面试题 1.实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number.String.Object.Array.Boolean)进行值复制 ...
- 互联网公司前端初级Javascript面试题
互联网公司前端初级Javascript面试题 1.JavaScript是一门什么样的语言,它有哪些特点?(简述javascript语言的特点)JavaScript是一种基于对象(Object)和事件驱 ...
- 174道 JavaScript 面试题,助你查漏补缺
最近在整理 JavaScript 的时候发现遇到了很多面试中常见的面试题,本部分主要是作者在 Github 等各大论坛收录的 JavaScript 相关知识和一些相关面试题时所做的笔记,分享这份总结给 ...
- 你应该知道的25道Javascript面试题
题目来自 25 Essential JavaScript Interview Questions.闲来无事,正好切一下. 一 What is a potential pitfall with usin ...
随机推荐
- POPTEST老李谈Debug和Release的区别(c#) 1
POPTEST老李谈Debug和Release的区别(c#) poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣 ...
- 老李分享:持续集成学好jenkins
老李分享:持续集成学好jenkins poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.poptest测试开发工程师就业培训请大 ...
- linux 压缩与解压
tar -cvf test.tar test ----将test文件夹打包成test.tar. # tar -xvf test.tar ----将test.tar 进行拆解,从中抽取文件 # ...
- 《完全用Linux工作》
<完全用Linux工作>作者:王垠 完全用 GNU/Linux 工作 理解 GNU/Linux 更多精彩请直接访问SkySeraph个人站点:www.skyseraph.com 注:本文是 ...
- linux常用脚本
转载于http://justcoding.iteye.com/blog/1943504 我们在运维中,尤其是linux运维,都知道脚本的重要性,脚本会让我们的 运维事半功倍,所以学会写脚本是我们每个l ...
- 跟着刚哥梳理java知识点——数组(七)
数组:数组是多个相同类型数据类型的集合,实现对这些数据的统一管理. 元素:数组中的元素可以是任何数据类型,包括基本数据类型和引用类型. 特点:属于引用类型,数组型数据是对象object,数组中的每个元 ...
- Git协作
前面的话 本文将详细介绍Git多人协作的具体内容 远程仓库 当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin. ...
- 【转】JDBC学习笔记(5)——利用反射及JDBC元数据编写通用的查询方法
转自:http://www.cnblogs.com/ysw-go/ JDBC元数据 1)DatabaseMetaData /** * 了解即可:DatabaseMetaData是描述数据库的元数据对象 ...
- Objective-C 实用关键字详解1「面试、工作」看我就 🐒 了 ^_^.
在写项目 或 阅读别人的代码(一些优秀的源码)中,总能发现一些常见的关键字,随着编程经验的积累大部分还是知道是什么意思 的. 相信很多开发者跟我当初一样,只是基本的常用关键字定义属性会使用,但在关键字 ...
- springmvc学习笔记(简介及使用)
springmvc学习笔记(简介及使用) 工作之余, 回顾了一下springmvc的相关内容, 这次也为后面复习什么的做个标记, 也希望能与大家交流学习, 通过回帖留言等方式表达自己的观点或学习心得. ...