溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

26個(gè)精選的JavaScript面試問題

發(fā)布時(shí)間:2020-06-08 19:42:40 來源:網(wǎng)絡(luò) 閱讀:596 作者:wx5d61fdc401976 欄目:web開發(fā)

為了保證可讀性,本文采用意譯而非直譯。另外,本文版權(quán)歸原作者所有,翻譯僅用于學(xué)習(xí)。

根據(jù)Stack Overflow 2018年年度調(diào)查報(bào)告,JavaScript已經(jīng)連續(xù)6年保持最常用的編程語言的記錄。對(duì)于一個(gè)全棧工程師,JavaScript可以說是一項(xiàng)必備語言,在面試中總會(huì)被問到。我整理了一下FullStack.Cafe上所有常見的JavaScript面試問題供大家參考:

Q1: JavaScript中類型轉(zhuǎn)換是怎樣的?
話題: JavaScript
難度: 0
在JavaScript中,在兩個(gè)不同類型之間的轉(zhuǎn)換叫做coercion。在JavaScript中有兩種形式:顯示轉(zhuǎn)換和隱式轉(zhuǎn)換。

下面是一個(gè)顯示轉(zhuǎn)換的例子:

var a = "42";
var b = Number( a );
a; // "42"
b; // 42 -- the number!
下面是一個(gè)隱式轉(zhuǎn)換的例子:

var a = "42";
var b = a * 1; // "42" implicitly coerced to 42 here
a; // "42"
b; // 42 -- the number!
來源: FullStack.Cafe

Q2: JavaScript中的作用域是怎樣的?
話題: JavaScript
難度: ?
在JavaScript中,每一個(gè)函數(shù)都有各自的作用域(scope)。作用域可以理解為是一個(gè)變量的集合以及相應(yīng)的如何訪問它的規(guī)則。只有在函數(shù)內(nèi)部的變量才可以訪問到該函數(shù)域的變量。

在同一個(gè)作用域內(nèi)部,變量名必須要唯一。作用域可以嵌套。在最內(nèi)部的作用域中,可以訪問任何外部的作用域中的變量。

Q3: 請(qǐng)解釋JavaScript中的相等判斷
話題: JavaScript
難度: ?
JavaScript中的相等判斷有嚴(yán)格判斷和帶隱式轉(zhuǎn)換的判斷兩種:

嚴(yán)格判斷(strict comparision): 比如===,比較的時(shí)候不會(huì)隱式轉(zhuǎn)換類型;
抽象判斷(abstract comparasion):比如==,比較的時(shí)候會(huì)隱式轉(zhuǎn)換類型。
var a = "42";
var b = 42;

a == b; // true
a === b; // false
一些簡單的規(guī)則:

如果兩邊都是布爾類型的值,使用===;
如果兩邊是0,"",[],使用===;
所有其它類型,使用==是安全的。而且在很多情況下會(huì)簡化代碼、增加可讀性。
Q4: 請(qǐng)解釋什么叫做回調(diào)函數(shù)并提供一個(gè)簡單的例子
話題: JavaScript
難度: ??
回調(diào)函數(shù)是一個(gè)函數(shù),它被作為參數(shù)傳入另一個(gè)函數(shù),當(dāng)某些操作結(jié)束后,該函數(shù)被調(diào)用。下面是一個(gè)簡單的例子,當(dāng)數(shù)組被修改后,調(diào)用回調(diào)函數(shù)打印一行日志。

function modifyArray(arr, callback) {
// do something to arr here
arr.push(100);
// then execute the callback function that was passed
callback();
}

var arr = [1, 2, 3, 4, 5];
modifyArray(arr, function() {
console.log("array has been modified", arr);
});
Q5: “use strict”到底有何用處?
話題: JavaScript
難度: ??
use strict放在文件的頂部或則函數(shù)的第一行來啟動(dòng)更加嚴(yán)格的檢查來避免失誤引起的錯(cuò)誤。比如,下面的代碼會(huì)拋出錯(cuò)誤:

function doSomething(val) {
"use strict";
x = val + 10;
}
因?yàn)閤沒有定義,如果使用了use strict,x是不會(huì)被當(dāng)做全局的變量來看待。下面的代碼修復(fù)了這個(gè)BUG:

function doSomething(val) {
"use strict";
var x = val + 10;
}
Q6: 請(qǐng)解釋Null和Undefined
話題: JavaScript
難度: ??
JavaScript和TypeScript有兩個(gè)最基本的類型null和undefined。它們的含義是不同的:

如果還沒有被初始化,則是undefined;
如果不可用,則可以用null來表示;
Q7: 請(qǐng)實(shí)現(xiàn)如下函數(shù)
話題: JavaScript
難度: ??
var addSix = createBase(6);
addSix(10); // returns 16
addSix(21); // returns 27
addSix是一個(gè)函數(shù),也就是說createBase函數(shù)的返回是一個(gè)函數(shù)。

function createBase(baseNumber) {
return function(N) {
// we are referencing baseNumber here even though it was declared
// outside of this function. Closures allow us to do this in JavaScript
return baseNumber + N;
}
}

var addSix = createBase(6);
addSix(10);
addSix(21);
Q8: 請(qǐng)解釋JavaScript中的值和類型
話題: JavaScript
難度: ??
下面是JavaScript內(nèi)置的可用類型:

string
number
boolean
null和undefined
object
symbol (ES6的新語法)
Q9: 請(qǐng)解釋事件冒泡以及如何阻止它?
話題: JavaScript
難度: ??
事件冒泡的概念是指:在最內(nèi)層的元素上綁定的事件被觸發(fā)后,會(huì)按照嵌套的層次由內(nèi)向外逐步觸發(fā)。因此,點(diǎn)擊某個(gè)孩子節(jié)點(diǎn)可能會(huì)觸發(fā)父節(jié)點(diǎn)的事件。

一個(gè)阻止事件冒泡的辦法就是使用event.stopPropagation(),在IE<9的瀏覽器上使用event.cancelBubble()。

Q10. 請(qǐng)解釋JavaScript中的let關(guān)鍵字
話題: JavaScript
難度: ??
ES6允許你使用let關(guān)鍵字來申明塊作用域({...})的變量。

來源: github.com/getify

Q11: 如何檢查一個(gè)數(shù)字是否是整數(shù)?
話題: JavaScript
難度: ??
一個(gè)最簡單的方法是判斷除以1的余數(shù)是否為0.

function isInt(num) {
return num % 1 === 0;
}

console.log(isInt(4)); // true
console.log(isInt(12.2)); // false
console.log(isInt(0.3)); // false
來源: coderbyte.com

Q12: 什么叫IIFEs(Immediately Invoked Function Expressions)?
話題: JavaScript
難度: ??
IIFE叫做立即執(zhí)行表達(dá)式,顧名思義,該表達(dá)式一被創(chuàng)建就立即執(zhí)行。

(function IIFE(){
console.log( "Hello!" );
})();
// "Hello!"
該方法常用語避免污染全局的命名空間,因?yàn)樗栽贗IFE中使用的變量外部都無法訪問。

來源: stackoverflow.com

Q13: 如果比較JavaScript中的兩個(gè)對(duì)象?
話題: JavaScript
難度: ??
兩個(gè)非基本類型的值,比如對(duì)象(包括函數(shù)和數(shù)組)都是通過引用的形式來訪問。如果直接通過==和===來判斷,那么只會(huì)簡單的判斷其引用地址是否相同,而不是它們實(shí)際對(duì)應(yīng)的值。

如果數(shù)組和字符串做比較,那么數(shù)組會(huì)通過逗號(hào)拼接轉(zhuǎn)換為字符串。通過等號(hào)判斷的時(shí)候,兩個(gè)相同的數(shù)組不會(huì)相等,但是和相同數(shù)據(jù)的字符串比較反而相等。

var a = [1,2,3];
var b = [1,2,3];
var c = "1,2,3";

a == c; // true
b == c; // true
a == b; // false
如果要深度比較,可以使用第三方庫,比如deep-equal或則你自己實(shí)現(xiàn)一個(gè)比較算法。

Q14: 請(qǐng)解釋ES5和ES6的不同點(diǎn)
話題: JavaScript
難度: ???
ECMAScript 5 (ES5): 第5個(gè)ECMAScript版本,于2009年標(biāo)準(zhǔn)化。該標(biāo)準(zhǔn)幾乎所有的瀏覽器都完全支持。
ECMAScript 6 (ES6)/ECMAScript 2015 (ES2015): 第6個(gè)ECMAScript版本,于2015年標(biāo)準(zhǔn)化。目前各大瀏覽器還只是部分支持。
接下來介紹它們主要的區(qū)別:

箭頭函數(shù)和字符串嵌入:
const greetings = (name) => {
return hello ${name};
}
甚至:

const greetings = name => hello ${name};
常量聲明(Const): 如同其它編程語言中的常量一樣,但又有不同。這里的const代表了constant reference。也就是說,你可以修改其指向的對(duì)象的值。但是你不能修改其reference的值。
const NAMES = [];
NAMES.push("Jim");
console.log(NAMES.length === 1); // true
NAMES = ["Steve", "John"]; // error
塊作用域變量:ES6中的新關(guān)鍵字let允許允許開發(fā)者將變量的作用域限定在塊級(jí)別。不會(huì)像var一樣變量提升。
參數(shù)默認(rèn)值:允許在函數(shù)定義的時(shí)候指定默認(rèn)的值。
// Basic syntax
function multiply (a, b = 2) {
return a * b;
}
multiply(5); // 10
類定義和繼承
ES6開始支持定義類(使用class關(guān)鍵字),構(gòu)造函數(shù)(使用constructor關(guān)鍵字),和extend關(guān)鍵字來實(shí)現(xiàn)繼承。

for-of操作
for...of語句用來迭代訪問一個(gè)對(duì)象的所有屬性。

Spread操作符:用于對(duì)象合并
const obj1 = { a: 1, b: 2 }
const obj2 = { a: 2, c: 3, d: 4}
const obj3 = {...obj1, ...obj2}
Promise: Promises提供了一個(gè)處理異步操作的方法。你可以用回調(diào)函數(shù)來實(shí)現(xiàn),但是Promise更加簡潔和可讀。
const isGreater = (a, b) => {
return new Promise ((resolve, reject) => {
if(a > b) {
resolve(true)
} else {
reject(false)
}
})
}
isGreater(1, 2)
.then(result => {
console.log('greater')
})
.catch(result => {
console.log('smaller')
})
模塊的export和import。
const myModule = { x: 1, y: () => { console.log('This is ES5') }}
export default myModule;

import myModule from './myModule';
來源: Bulby.io

Q15: 請(qǐng)解釋undefined和not defined的區(qū)別
話題: JavaScript
難度: ???
在JavaScript中,如果你嘗試使用不存在的還未申明的變量,JavaScript會(huì)拋出錯(cuò)誤var name is not defined。但是如果你用typeof來查看其類型,會(huì)返回undefined。

我們先來澄清一下聲明和定義的區(qū)別:var x是一個(gè)聲明,因?yàn)槟悴]有定義其具體的值,你只是聲明其存在性。

var x; // declaring x
console.log(x); //output: undefined
var x = 1同時(shí)兼具聲明和定義,我們也可以叫它初始化。在JavaScript中,每一個(gè)變量和函數(shù)聲明都會(huì)被提升到頂部。

如果我們?cè)L問一個(gè)聲明了但是未定義的變量,會(huì)返回undefined。

var x; // Declaration
if(typeof x === 'undefined') // Will return true
訪問一個(gè)未聲明未定義的變量,會(huì)返回not defined錯(cuò)誤。
console.log(y); // Output: ReferenceError: y is not defined
來源: stackoverflow.com

Q16: 匿名函數(shù)和命名函數(shù)的區(qū)別?
話題: JavaScript
難度: ???
var foo = function() { // anonymous function assigned to variable foo
// ..
};

var x = function bar(){ // named function (bar) assigned to variable x
// ..
};

foo(); // actual function execution
x();
譯者補(bǔ)充:匿名函數(shù)如果不賦值給某個(gè)變量,則無法被調(diào)用了;命名函數(shù)再次被賦值不是多此一舉么。

Q17: JavaScript中閉包是什么?請(qǐng)?zhí)峁┮粋€(gè)例子
話題: JavaScript
難度: ????
閉包是一個(gè)定義在其它函數(shù)(父函數(shù))里面的函數(shù),它擁有對(duì)父函數(shù)里面變量的訪問權(quán)。閉包擁有如下三個(gè)作用域的訪問權(quán):

自身的作用域
父作用域
全局作用域
var globalVar = "abc";

// Parent self invoking function
(function outerFunction (outerArg) { // begin of scope outerFunction
// Variable declared in outerFunction function scope
var outerFuncVar = 'x';
// Closure self-invoking function
(function innerFunction (innerArg) { // begin of scope innerFunction
// variable declared in innerFunction function scope
var innerFuncVar = "y";
console.log(
"outerArg = " + outerArg + "\n" +
"outerFuncVar = " + outerFuncVar + "\n" +
"innerArg = " + innerArg + "\n" +
"innerFuncVar = " + innerFuncVar + "\n" +
"globalVar = " + globalVar);
// end of scope innerFunction
})(5); // Pass 5 as parameter
// end of scope outerFunction
})(7); // Pass 7 as parameter
innerFunction是一個(gè)閉包,定義在outerFunction中,它可以訪問outerFunction作用域的所有變量。當(dāng)然,它還可以訪問全局變量。

輸出結(jié)果如下:

outerArg = 7
outerFuncVar = x
innerArg = 5
innerFuncVar = y
globalVar = abc
來源: github.com/ganqqwerty

Q18: 在JavaScript中如何創(chuàng)建私有變量?
話題: JavaScript
難度: ????
你可以通過在函數(shù)中聲明變量來創(chuàng)建私有變量。因?yàn)樵诤瘮?shù)中,外部無法直接訪問。

function func() {
var priv = "secret code";
}

console.log(priv); // throws error
為了訪問該變量,可以構(gòu)造一個(gè)幫助函數(shù)來返回該值。

function func() {
var priv = "secret code";
return function() {
return priv;
}
}

var getPriv = func();
console.log(getPriv()); // => secret code
來源:coderbyte.com

Q19: 請(qǐng)解釋原型模式(Prototype Design Pattern)
話題: JavaScript
難度: ????
原型模式會(huì)創(chuàng)建一個(gè)新的對(duì)象,但不是創(chuàng)建一個(gè)未初始化的對(duì)象,而是通過拷貝原型鏈上的值或則被拷貝對(duì)象的值來完成初始化。傳統(tǒng)的語言很少使用原型模式,但是JavaScript作為一個(gè)基于原型的語言,使用原型模式來創(chuàng)建新的對(duì)象。

來源: dofactory.com

Q20: 判斷給定的字符串是否同態(tài)(isomorphic)
話題: JavaScript
難度: ????
首先介紹什么叫做同態(tài):兩個(gè)字符串,如果A字符串中的每一個(gè)字符都可以在B字符串中找到唯一對(duì)應(yīng),并且順序一一對(duì)應(yīng);如果存在這樣的函數(shù),那么A和B同態(tài)。

paper和title同態(tài)
egg和sad不同態(tài)
dgg和add同態(tài)
isIsomorphic("egg", 'add'); // true
isIsomorphic("paper", 'title'); // true
isIsomorphic("kick", 'side'); // false

function isIsomorphic(firstString, secondString) {

// Check if the same length. If not, they cannot be isomorphic
if (firstString.length !== secondString.length) return false

var letterMap = {};

for (var i = 0; i < firstString.length; i++) {
var letterA = firstString[i],
letterB = secondString[i];

// If the letter does not exist, create a map and map it to the value
// of the second letter
if (letterMap[letterA] === undefined) {
  letterMap[letterA] = letterB;
} else if (letterMap[letterA] !== letterB) {
  // Eles if letterA already exists in the map, but it does not map to
  // letterB, that means that A is mapping to more than one letter.
  return false;
}

}
// If after iterating through and conditions are satisfied, return true.
// They are isomorphic
return true;
}
來源: https://github.com/kennymkchan

譯者注:上面的解法并不正確,針對(duì)上面的代碼,我們略做改動(dòng),給出如下正確答案:

/**

  • @param {string} firstString
  • @param {string} secondString
  • @return {boolean}
    */
    var isIsomorphic = function(firstString, secondString) {
    // Check if the same length. If not, they cannot be isomorphic
    if (firstString.length !== secondString.length) return false

    var letterMap = {};

    for (var i = 0; i < firstString.length; i++) {
    var letterA = firstString[i],
    letterB = secondString[i];

    // If the letter does not exist, create a map and map it to the value
    // of the second letter
    if (letterMap[letterA] === undefined) {
    // If letterB has already been added to letterMap, then not isomorphic
    if(secondString.indexOf(letterB) < i){
    return false;
    } else {
    letterMap[letterA] = letterB;
    }
    } else if (letterMap[letterA] !== letterB) {
    // Else if letterA already exists in the map, but it does not map to
    // letterB, that means that A is mapping to more than one letter.
    return false;
    }
    }
    // If after iterating through and conditions are satisfied, return true.
    // They are isomorphic
    return true;
    };
    Leetcode上有相應(yīng)的題目:Isomorphic Strings - LeetCode

Q21: Transpiling代表了什么意思?
話題: JavaScript
難度: ????
Transpiling是transforming + compiling的合成詞。對(duì)于一些新的語法,瀏覽器還不支持。最好的辦法就是將其變換到舊的等價(jià)的代碼,這個(gè)過程通常叫做transpiling。

典型的,你可以在build的過程中加入transpiler,就如同code linter和minifier一樣。

已經(jīng)有很多知名的transpilers可供使用:

Babel: 將ES6編譯到ES5
Traceur:將ES6,ES7等編譯到ES5
來源: You Don’t Know JS, Up &going

Q22: this關(guān)鍵字如何工作?請(qǐng)?zhí)峁┮恍├?br/>話題: JavaScript
難度: ????
在JavaScript中,this總是指向函數(shù)的“擁有者”(也就是指向該函數(shù)的對(duì)象),或則擁有該函數(shù)的對(duì)象。

function foo() {
console.log( this.bar );
}

var bar = "global";

var obj1 = {
bar: "obj1",
foo: foo
};

var obj2 = {
bar: "obj2"
};

foo(); // "global"
obj1.foo(); // "obj1"
foo.call( obj2 ); // "obj2"
new foo(); // undefined
來源: quirksmode.org

Q23: 如何為Array對(duì)象添加你自定義的函數(shù),使得如下代碼可以正常工作。
話題: JavaScript
難度: ????
var arr = [1, 2, 3, 4, 5];
var avg = arr.average();
console.log(avg);
JavaScript是一個(gè)基于原型的語言。也就是說對(duì)象之間通過原型鏈接,并繼承其函數(shù)。為了給Array對(duì)象添加函數(shù),我們可以修改其原型定義Array prorotype。

Array.prototype.average = function() {
// calculate sum
var sum = this.reduce(function(prev, cur) { return prev + cur; });
// return sum divided by number of elements
return sum / this.length;
}

var arr = [1, 2, 3, 4, 5];
var avg = arr.average();
console.log(avg); // => 3
來源: coderbyte.com

Q24: JavaScript中提升(hoisting)是什么意思?
話題: JavaScript
難度: ????
提升(hoisting)是指JavaScript的解釋器將所有的變量和函數(shù)聲明都提升到該作用域的頂部,有兩種提升類型:

變量提升
函數(shù)提升
在一個(gè)作用域中通過聲明的變量和函數(shù)在整個(gè)作用域中都可以使用。

var a = 2;
foo(); // works because foo()
// declaration is "hoisted"

function foo() {
a = 3;
console.log( a ); // 3
var a; // declaration is "hoisted"
// to the top of foo()
}

console.log( a ); // 2
雖然foo()函數(shù)在后面定義,但是在前面也可以調(diào)用。

Q25: 如下代碼會(huì)返回什么結(jié)果?
話題: JavaScript
難度: ????
0.1 + 0.2 === 0.3
不要驚訝,其結(jié)果是false。因?yàn)楦↑c(diǎn)數(shù)在系統(tǒng)內(nèi)的精確度問題,0.1+0.2的結(jié)果并不是0.3,而是0.30000000000000004。
要避免這個(gè)問題的方法是指定返回結(jié)果的小數(shù)位數(shù)。

來源: coderbyte.com

Q26: 請(qǐng)描述一下揭示模式(Revealing Module Pattern)
話題: JavaScript
難度: ?????
Module pattern的一個(gè)變種是Revealing Module Pattern。該設(shè)計(jì)模式的目的是做到很好的代碼隔離,只是將需要對(duì)外公開的變量和函數(shù)暴露出來。一個(gè)直接的實(shí)現(xiàn)如下所示:

var Exposer = (function() {
var privateVariable = 10;

var privateMethod = function() {
console.log('Inside a private method!');
privateVariable++;
}

var methodToExpose = function() {
console.log('This is a method I want to expose!');
}

var otherMethodIWantToExpose = function() {
privateMethod();
}

return {
first: methodToExpose,
second: otherMethodIWantToExpose
};
})();

Exposer.first(); // Output: This is a method I want to expose!
Exposer.second(); // Output: Inside a private method!
Exposer.methodToExpose; // undefined
26個(gè)精選的JavaScript面試問題

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI