题目来自 25 Essential JavaScript Interview Questions。闲来无事,正好切一下。


What is a potential pitfall with using typeof bar === "object" to determine if bar is an object? How can this pitfall be avoided?

老生常谈的问题,用 typeof 是否能准确判断一个对象变量,答案是否定的,null 的结果也是 object,Array 的结果也是 object,有时候我们需要的是 "纯粹" 的 object 对象。

如何规避这个问题?

var obj = {};// 1
console.log((obj !== null) && (typeof obj === "object") && (toString.call(obj) !== "[object Array]"));// 2
console.log(Object.prototype.toString.call(obj) === "[object Object]");


What will the code below output to the console and why?

(function(){var a = b = 3;
})();console.log("a defined? " + (typeof a !== 'undefined'));
console.log("b defined? " + (typeof b !== 'undefined'));

这题不难,IIFE 中的赋值过程其实是(赋值过程从右到左):

(function(){b = 3;var a = b;
})();

接下去就不难了,a 是局部变量,b 是全局变量。


What will the code below output to the console and why?

var myObject = {foo: "bar",func: function() {var self = this;console.log("outer func:  this.foo = " + this.foo);console.log("outer func:  self.foo = " + self.foo);(function() {console.log("inner func:  this.foo = " + this.foo);console.log("inner func:  self.foo = " + self.foo);}());}
};
myObject.func();

前面两个输出没有问题,都是 bar,问题出在后面两个。用了 IIFE 后,匿名函数内的 this 其实已经指到了 window,所以第三个输出 this.foo 其实是 window.foo,而全局对象并没有 foo 这个 key,所以输出 undefined,而第四个输出,因为 self 引用了 myObject,所以还是 bar。


What is the significance of, and reason for, wrapping the entire content of a JavaScript source file in a function block?

为什么要用 IIFE?

简单来说就是为了能模块化,创建私有变量等等,很多类库(比如 jQuery)都用了这样的写法。

可以参考我以前翻译的一篇文章 详解javascript立即执行函数表达式(IIFE)


What is the significance, and what are the benefits, of including 'use strict' at the beginning of a JavaScript source file?

严格模式下进行 Javascript 开发有啥好处?

这个就不展开来了,可以参考阮一峰老师的 Javascript 严格模式详解 或者自行谷歌百度。


Consider the two functions below. Will they both return the same thing? Why or why not?

function foo1()
{return {bar: "hello"};
}function foo2()
{return{bar: "hello"};
}

执行以上两个函数,会返回相同的东西吗?

不会,第二个函数会返回 undefined。这是由于 Javascript 的封号插入机制决定的,如果某行代码,return 关键词后没有任何东西了,将会自动插入一个封号,显然 foo2 函数中,当 return 后被插入一个封号后,尽管后面的语句不符合规定,但是因为没有执行到,所以也不会报错了。没有 return 任何东西的函数,默认返回 undefined。

所以很多 Javascript 规范建议把 { 写在一行中,而不是另起一行。


What is NaN? What is its type? How can you reliably test if a value is equal to NaN?

NaN 是什么鬼?typeof 的结果是?如果一个变量的值是 NaN,怎么确定?

NaN 是 'not a number' 的缩写,表示 "不是一个数字",通常会在运算过程中产生:

console.log('abc' / 4);
console.log(4 * 'a');

虽然它 "不是一个数字",但是 NaN 的 typeof 结果却是 number:

console.log(typeof (4 * 'a')); // number

NaN 和任何变量都不相等,包括 NaN 自己:

console.log(NaN === NaN); // false

判断一个变量是不是 NaN 可以用 isNaN() 函数,但是这 并不是一个完美的函数,有些时候用 value !== value 似乎更准确,幸运的是,ES6 已经有 Number.isNaN() 方法,将比 isNaN() 准确的多。


What will the code below output? Explain your answer.

console.log(0.1 + 0.2);
console.log(0.1 + 0.2 == 0.3);

上面代码的输出结果是什么?

这个问题正好我之前研究过,有兴趣的可以参考下 【0.1 + 0.2 = 0.30000000000000004】该怎样理解?,看懂了还有兴趣的可以看下这篇 玉伯的一道课后题题解(关于 IEEE 754 双精度浮点型精度损失)


Discuss possible ways to write a function isInteger(x) that determines if x is an integer.

写一个方法 isInterger(x),可以用来判断一个变量是否是整数。

ES6 中自带了 Number.isInteger() 方法。但是目前 ES5 中没有自带的方法,可以把一个数去掉小数点后和原数进行比较,判断是否相等,那么问题就演变成如何对一个数进行取整了。

 var a = -1.2223;console.log(a ^ 0);  // -1console.log(a | 0);  // -1console.log(a << 0); // -1console.log(a >> 0); // -1console.log(Math.round(a)); // -1console.log(Math.floor(a)); // -2console.log(Math.ceil(a));  // -1


In what order will the numbers 1-4 be logged to the console when the code below is executed? Why?

(function() {console.log(1); setTimeout(function(){console.log(2)}, 1000); setTimeout(function(){console.log(3)}, 0); console.log(4);
})();

以上代码的输出结果是?

这题不难,只要知道 Javascript 是单线程的语言, 一些异步事件是在主体 js 执行完之后执行即可,所以主体的 1、4 先输出,而后是 3、2,没有问题,因为 3 的定时设置比 2 早。

具体可以参考我之前的文章 从setTimeout谈JavaScript运行机制

十一


Write a simple function (less than 80 characters) that returns a boolean indicating whether or not a string is a palindrome.

判断一个字符串是不是回文。

function isPalindrome(str) {str = str.replace(/\W/g, '').toLowerCase();return (str == str.split('').reverse().join(''));
}

这里想到一个进阶题,求字符串最长回文子串,可以参考 求最长回文子串 - leetcode 5. Longest Palindromic Substring

十二


Write a sum method which will work properly when invoked using either syntax below.

console.log(sum(2,3));   // Outputs 5
console.log(sum(2)(3));  // Outputs 5

写一个 sum 方法,使得以上代码得到预期结果。这题可以参考我以前的文章 汤姆大叔的6道javascript编程题题解 中的最后一题,理论上此题更简单,因为它没要求能扩展(比如 sum(2)(3)(4)),甚至可以这样:

function sum(x) {if (arguments.length == 2) {return arguments[0] + arguments[1];} else {return function(y) { return x + y; };}
}

或者这样:

function sum(x, y) {if (y !== undefined) {return x + y;} else {return function(y) { return x + y; };}
}

十三


Consider the following code snippet:

for (var i = 0; i < 5; i++) {var btn = document.createElement('button');btn.appendChild(document.createTextNode('Button ' + i));btn.addEventListener('click', function(){ console.log(i); });document.body.appendChild(btn);
}

(a) What gets logged to the console when the user clicks on “Button 4” and why?

(b) Provide one or more alternate implementations that will work as expected.

点击 'Button 4' 后输出什么?如何使得输出能跟预期相同?

答案是输出 5,事实上点击任意的 button,输出都是 5。因为循环结束后,i 值变成了 5。如何改,使得输出分别是 0, 1, 2, 3, 4?用闭包在内存中保存变量,可以参考我之前的文章 这10道javascript笔试题你都会么 中的第 8 题。

十四


What will the code below output to the console and why?

var arr1 = "john".split('');
var arr2 = arr1.reverse();
var arr3 = "jones".split('');
arr2.push(arr3);
console.log("array 1: length=" + arr1.length + " last=" + arr1.slice(-1));
console.log("array 2: length=" + arr2.length + " last=" + arr2.slice(-1));

上面代码输出是?

这道题我答错了,忽略了 reverse() 方法的一个要重性质,reverse() 方法执行的结果并不是创建一个副本,而是在原数组上直接操作,并返回该数组的引用。

知道了这一点,该题也就迎刃而解了。arr2 其实和 arr1 引用了同一个对象,所以在 arr2 上的操作也会同时反映到 arr1 上。

十五


What will the code below output to the console and why ?

console.log(1 +  "2" + "2");
console.log(1 +  +"2" + "2");
console.log(1 +  -"1" + "2");
console.log(+"1" +  "1" + "2");
console.log( "A" - "B" + "2");
console.log( "A" - "B" + 2);

以上代码输出什么?

+"2" 能将字符串 "2" 转换成整数 2,-"2" 同理,而两个变量进行 "+" 运算时,如果都是数字和字符串,则分别进行数字相加和字符串拼接,如果一个是数字一个是字符串,则将数字转为字符串,如果是 "-" 运算呢?则将字符串转为数字。

"A" - "B" 会返回 NaN,因为 "A" 和 "B" 无法转成数字进行运算,这里不要以为 "A" 和 "B" 能转为 ASCII码 进行运算(不要和 C 语言搞混了)。而 NaN 和字符串相加,会转成 "NaN" 和字符串去拼接,NaN 和任何数字相加结果还是 NaN。

十六


The following recursive code will cause a stack overflow if the array list is too large. How can you fix this and still retain the recursive pattern?

var list = readHugeList();var nextListItem = function() {var item = list.pop();if (item) {// process the list item...nextListItem();}
};

以上代码可能会由于递归调用导致栈溢出,如何规避这个问题?

首先,任何递归都可以用迭代来代替,所以改写成迭代方式肯定没有问题。

而原文给的解答令人深思:

var list = readHugeList();var nextListItem = function() {var item = list.pop();if (item) {// process the list item...setTimeout( nextListItem, 0);}
};

利用 setTimeout 的异步性质,完美地去除了这个调用栈。

如果你还是摸不着头脑,简单举个栗子:

var list = [0, 1];var nextListItem = function() {var item = list.pop();if (item) {nextListItem();}console.log(item);
};nextListItem();

上面的代码会依次输出 0 和 1,因为程序中形成了一个调用栈,1 被压到了栈底,最后出栈。

把程序改成这样:

var list = [0, 1];var nextListItem = function() {var item = list.pop();if (item) {// process the list item...setTimeout( nextListItem, 0);}console.log(item);
};nextListItem();

这回就是 1 和 0 了,因为 setTimeout 的回调只有当主体的 js 执行完后才会去执行,所以先输出了 1,自然也就没有栈这一说法了。

事实上,并不是所有递归都能这样改写,如果下一次递归调用依赖于前一次递归调用返回的值,就不能这么改了。

十七


What is a “closure” in JavaScript? Provide an example.

谈谈闭包。

以前也写过几篇文章,可以参考下 闭包初窥 以及 闭包拾遗 & 垃圾回收机制。

十八


What will be the output of the following code:

for (var i = 0; i < 5; i++) {setTimeout(function() { console.log(i); }, i * 1000 );
}

Explain your answer. How could the use of closures help here?

以上代码输出什么?如何能输出期望值?

很显然,输出都是 5。这题和第十三题有些类似,用立即执行函数+闭包即可。

for (var i = 0; i < 5; i++) {!function(i) {setTimeout(function() { console.log(i); }, i * 1000 );}(i)
}

还有种优雅的解法,使用 bind:

for(var i = 0; i < 5; i++) {setTimeout(console.log.bind(console, i), i * 1000);
}

十九


What would the following lines of code output to the console?

console.log("0 || 1 = "+(0 || 1));
console.log("1 || 2 = "+(1 || 2));
console.log("0 && 1 = "+(0 && 1));
console.log("1 && 2 = "+(1 && 2));

以上代码输出什么?

||&& 是短路运算符。先说说 ||,如果前面变量值为 false(包括 0、null、undefined、flase、空字符串等等),则返回后面变量值,否则返回前面变量值。&& 恰恰相反,如果前面变量为 false,则返回前面变量值,否则返回后面变量值。

注意不要和位运算操作符 | 以及 & 搞混淆了。

二十


What will be the output when the following code is executed? Explain.

console.log(false == '0')
console.log(false === '0')

===== 的区别, 后者是全等,只有两个值完全相同(或者两个对象引用相同)时,才会返回 true,而前者在比较时会进行隐式的转换。

二十一


What is the output out of the following code? Explain your answer.

var a={},b={key:'b'},c={key:'c'};a[b]=123;
a[c]=456;console.log(a[b]);

一道有趣的题目,答案是 456。

我们知道,Javascript 中对象的 key 值,一定会是一个 string 值,如果不是,则会隐式地进行转换。当执行到 a[b]=123] 时,b 并不是一个 string 值,将 b 执行 toString() 方法转换(得到 "[object Object]"),a[c] 也是相同道理。所以代码其实可以看做这样执行:

var a={},b={key:'b'},c={key:'c'};// a[b]=123;
a["[object Object]"]=123;// a[c]=456;
a["[object Object]"]=456;console.log(a["[object Object]"]);

这样就一目了然了。

二十二


What will the following code output to the console:

console.log((function f(n){return ((n > 1) ? n * f(n-1) : n)})(10));

输出什么?

其实可以写成这样,清楚些:

var ans = (function f(n){return ((n > 1) ? n * f(n-1) : n)
})(10);console.log(ans);

其实就是一个立即执行函数+递归,求个阶乘而已(10!)。给立即执行函数加了个名字 f,方便在递归里调用,其实完全可以用 arguments.callee 代替:

var ans = (function(n){return ((n > 1) ? n * arguments.callee(n-1) : n)
})(10);console.log(ans);

二十三


Consider the code snippet below. What will the console output be and why?

(function(x) {return (function(y) {console.log(x);})(2)
})(1);

输出什么?

显然是 1,闭包,能引用函数外的变量。

改成这样呢?

(function(y) {return (function(y) {console.log(y);})(2)
})(1);

二十四


What will the following code output to the console and why:

var hero = {_name: 'John Doe',getSecretIdentity: function (){return this._name;}
};var stoleSecretIdentity = hero.getSecretIdentity;console.log(stoleSecretIdentity());
console.log(hero.getSecretIdentity());

What is the issue with this code and how can it be fixed.

执行第一次输出时,this 指向了 window,如何规避这个问题?用 bind 绑定 this 指向,具体可以参考 ECMAScript 5(ES5)中bind方法简介备忘,注意低版本 IE 的兼容。

var stoleSecretIdentity = hero.getSecretIdentity.bind(hero);

二十五


Create a function that, given a DOM Element on the page, will visit the element itself and all of its descendents (not just its immediate children). For each element visited, the function should pass that element to a provided callback function.

The arguments to the function should be:

  • a DOM element
  • a callback function (that takes a DOM element as its argument)

遍历 DOM 树,不难,深度优先搜索即可。

function Traverse(p_element,p_callback) {p_callback(p_element);var list = p_element.children;for (var i = 0; i < list.length; i++) {Traverse(list[i],p_callback);  // recursive call}
}

这道题可以拓展,先序遍历 DOM树,中序遍历,甚至后序遍历的结果是?具体可以参考前文 二叉树三种遍历的递归和迭代解法,都是树,原理是一样一样的。

原文链接:http://www.cnblogs.com/zichi/p/5079505.html

转载于:https://www.cnblogs.com/Percy_Lee/p/5081623.html

你应该知道的25道Javascript面试题相关推荐

  1. python面试题_面试时全对这25道python面试题,成就了我月薪25K!附教程分享)

    之前面试的时候,面试官拿出一些python面试题对我说,只要全部正确直接给我20K,我一看题目笑了,居然全部都会,今天拿出来给大家分享一下~ 面试时全对这25道python面试题,成就了我月薪20K! ...

  2. 看完这几道 JavaScript 面试题,让你与考官对答如流(中)

    作者:Mark A 译者:前端小智 来源:dev 由于篇幅过长,我将此系列分成上中下三篇,上篇: 看完这几道 JavaScript 面试题,让你与考官对答如流(上) 26. 什么是IIFE,它的用途是 ...

  3. 100 道 JavaScript 面试题及答案(下)

    编辑整理 | 杨小爱 我们接上昨天的上篇内容<100 道 JavaScript 面试题及答案(上)>,今天我们开启下篇,把后面的50道题认真看完. 现在,我们就开始吧. 51. promi ...

  4. 100道JavaScript 面试题和答案(下)

    英文 | https://betterprogramming.pub/100-javascript-interview-questions-58e22e30f7f1 翻译 | 杨小二 接上篇<1 ...

  5. 100 道 JavaScript 面试题及答案汇总(下)

    英文 | https://betterprogramming.pub/100-javascript-interview-questions-58e22e30f7f1 翻译 | 杨小二 接上篇< ...

  6. 每一个JavaScript开发者都应该知道的10道面试题

    JavaScript十分特别.而且差点儿在每一个大型应用中起着至关关键的数据.那么,究竟是什么使JavaScript显得与众不同,意义非凡? 这里有一些问题将帮助你了解其真正的奥妙所在:   1.你能 ...

  7. 你应该知道的25个非常有用的CSS技巧

    在我们的前端CSS编码当中,经常要设置特殊的字体效果,边框圆角等等,还要考虑兼容性的问题, CSS网页布局,说难,其实很简单.说它容易,往往有很多问题困扰着新手,在中介绍了非常多的技巧,这些小技巧与知 ...

  8. 174道 JavaScript 面试题,助你查漏补缺

    最近在整理 JavaScript 的时候发现遇到了很多面试中常见的面试题,本部分主要是作者在 Github 等各大论坛收录的 JavaScript 相关知识和一些相关面试题时所做的笔记,分享这份总结给 ...

  9. 100道+ JavaScript 面试题,助你查漏补缺

    来源 | https://github.com/Wscats/articles 最近在整理 JavaScript 的时候发现遇到了很多面试中常见的面试题,本文主要是在 Github 等各大论坛收录的 ...

最新文章

  1. Python实现im2col和col2im函数
  2. Python高级数据类型模块collections
  3. 函数⑥作用域与命名空间
  4. java 读取 xmltype_java操作XMLType的几种方法
  5. sqoop 把 hdfs 和关系型数据库 (mysql等)互导
  6. AutoCAD.net: 用于ObjectARX 开发的Visual Studio 智能感知文件
  7. day 07总结(数字类型内置方法/字符串类型内置方法)
  8. 将JQuery框架集成到SharePoint 2010中
  9. 摘录 vue.js代码片段的理解
  10. [渝粤教育] 江西理工大学 新融合大学英语(I) 参考 资料
  11. shark学习(1)【原创】
  12. mongodb 高可用分布式原理 ---------搭建高可用mongo集群前需要温习的知识-火
  13. 导入从postman导出的json接口文件,并设置全局变量
  14. U890采购入库单修改供应商
  15. git实用技巧:将多次commit合并为一次
  16. 请领导批阅文件怎么说_请领导批复文件怎么说
  17. 判断视频中是否存在移动物体
  18. C语言五子棋的项目背景,五子棋项目源码!
  19. [08S01] Communications link failure报错解决
  20. 计算机的音量打不开,电脑静音,音量打不开.怎么办?

热门文章

  1. Codeforces 427 D. Match amp; Catch
  2. [转]如何将属性表嵌入对话框中显示
  3. WEBTIMER控件研究的心得:丢开书本做一个WebTimer
  4. 11-1 操作系统概念
  5. write up: web 前女友(SKCTF)
  6. 里工实业:用宜搭自主搭建MES系统,实现生产全流程管理
  7. 云原生,开发者的黄金时代
  8. 国内唯一入选云厂商——阿里云入选 2021 Gartner APM 魔力象限
  9. php概率计算_php 抽奖概率算法
  10. Python,美国顶尖大学里最受欢迎的编程入门语言