您的当前位置:首页正文

你应该知道的25道Javascript面试题

2023-03-04 来源:一二三四网
你应该知道的25道Javascript⾯试题

题⽬来⾃ 。闲来⽆事,正好切⼀下。

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)都⽤了这样的写法。可以参考我以前翻译的⼀篇⽂章

What is the significance, and what are the benefits, of including 'use strict' at the beginning of a JavaScript source file?严格模式下进⾏ 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);

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

这个问题正好我之前研究过,有兴趣的可以参考下 ,看懂了还有兴趣的可以看下这篇

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); // -1 console.log(a | 0); // -1 console.log(a << 0); // -1 console.log(a >> 0); // -1 console.log(Math.round(a)); // -1 console.log(Math.floor(a)); // -2 console.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 早。具体可以参考我之前的⽂章

⼗⼀

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(''));}

这⾥想到⼀个进阶题,求字符串最长回⽂⼦串,可以参考

⼗⼆

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

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

写⼀个 sum ⽅法,使得以上代码得到预期结果。这题可以参考我以前的⽂章 中的最后⼀题,理论上此题更简单,因为它没要求能扩展(⽐如 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?⽤闭包在内存中保存变量,可以参考我之前的⽂章 中的第 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 recursivepattern?

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)}

还有种优雅的解法,使⽤ :

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 指向,具体可以参考 ,注意低版本 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 immediatechildren). 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树,中序遍历,甚⾄后序遍历的结果是?具体可以参考前⽂ ,都是树,原理是⼀样⼀样的。

因篇幅问题不能全部显示,请点此查看更多更全内容