英文 | https://betterprogramming.pub/100-javascript-interview-questions-58e22e30f7f1
翻譯 | 楊小二
這是一份包含 100 道程式設計面試問題和答案的完整清單。除了面試之外,如果你正在學習或者準備JavaScript考試,這個清單也會很友善。
即使你沒有參加程式設計面試或考試,這份清單也是值得的——它涵蓋了 JavaScript 的大部分重要概念。
現在,讓我們開始吧。
1、什麼是 JavaScript?
JavaScript 是一種用戶端/伺服器端程式設計語言。JavaScript 可以插入到 HTML 中,使網頁具有互動性并實作使用者參與。
2、JavaScript 中的提升是什麼?
提升意味着所有的聲明都被移動到作用域的頂部。這發生在代碼運作之前。
對于函數,這意味着你可以從作用域中的任何位置調用它們,甚至在它們被定義之前。
hello(); // Prints "Hello world! " even though the function is called "before" declaration
function hello(){
console.log("Hello world! ");
}
對于變量,提升有點不同。它在作用域的頂部将 undefined 配置設定給它們。
例如,在定義變量之前調用它:
console.log(dog);
var dog = "Spot";
結果是:
undefined
這可能令人驚訝,因為你可能預計它會導緻錯誤。
如果你聲明一個函數或變量,無論你在哪裡聲明它,它總是被移動到作用域的頂部。
3、isNan() 函數有什麼作用?
你可以使用 isNan() 函數來檢查值的類型是否為數字且是否為 NaN。
(是的, NaN 是數字類型,即使它的名稱是“非數字”。這是因為它在底層是數字類型,即使它沒有數字值。)
例如:
function toPounds(kilos) {
if (isNaN(kilos)) {
return 'Not a Number! Cannot be a weight.';
}
return kilos * 2.2;
}
console.log(toPounds('this is a test'));
console.log(toPounds('100'));
輸出:
Not a Number! Cannot be a weight.
220.00000000000003
4、JavaScript 中的負無窮是什麼?
如果在 JavaScript 中将負數除以零,則會得到負無窮大。
例如:
console.log(-10/0)
輸出:
-Infinity
5、 什麼是未聲明變量?一個未定義的變量怎麼樣?
程式中根本不存在未聲明的變量。如果你的程式嘗試讀取未聲明的變量,則會引發運作時錯誤。
調用未聲明變量的示例顯然會導緻錯誤:
console.log(dog);
輸出:
error: Uncaught ReferenceError: dog is not defined
- 未定義的變量。在程式中聲明但沒有值。如果程式嘗試讀取未定義的變量,則會傳回未定義的值并且應用程式不會崩潰。
未定義變量的一個例子是:
let car;
console.log(car);
輸出:
undefined
6、JavaScript 中有哪些類型的彈出框?
三種類型的彈出視窗是警報、确認和提示。讓我們看看每個的示例使用:
警報
例如:
window.alert("Hello, world!");
确認
例如:
if (window.confirm("Are you sure you want to go?")) {
window.open("exit.html", "See you again!");
}
提示
例如:
let person = window.prompt("Enter your name");
if (person != null) {
console.log('Hello', person);
}
7、 == 和 === 有什麼差別?
== 比較值
=== 比較值和類型
例子:
var x = 100;
var y = "100";
(x == y) // --> true because the value of x and y are the same
(x === y) // --> false because the type of x is "number" and type of y is "string"
8、隐式類型強制有什麼作用?舉個例子。
隐式類型強制意味着一個值在幕後從一種類型轉換為另一種類型。當表達式的操作數是不同類型時會發生這種情況。
例如,字元串強制意味着在數字上應用運算符 + ,字元串會自動将數字轉換為字元串。
例如:
var x = 1;
var y = "2";
x + y // Returns "12"
但是在處理減法時,強制以另一種方式起作用。它将字元串轉換為數字。
例如:
var x = 10;
var y = "10";
x - y // Returns 0
9、JavaScript 是靜态類型語言還是動态類型語言?這是什麼意思?
JavaScript 是動态類型的。
這意味着在運作時檢查對象的類型。(在靜态類型語言中,在編譯時檢查類型。)
換句話說,JavaScript 變量與類型無關。這意味着你可以毫無問題地更改資料類型。
var num = 10;
num = "Test";
在靜态類型語言(例如 C++)中,不可能以這種方式将整數更改為字元串。
10、JavaScript 中的 NaN 是什麼?
NaN 的意思是“非數字”。這意味着一個值在 JavaScript 中不是正式的數字。
可能令人困惑的是,使用 typeof() 函數對 NaN 進行類型檢查的結果是 Number。
console.log(typeof(NaN))
輸出:
Number
為避免混淆,請使用 isNaN() 來檢查值的類型是否為 NaN 或不是數字。
11、 JavaScript 中的展開運算符是什麼?
展開運算符允許将可疊代對象(數組/對象/字元串)擴充為單個參數/元素。讓我們舉個例子來看看這個行為。
function sum(a, b, c) {
return a + b + c;
}
const nums = [15, 25, 35];
console.log(sum(...nums));
輸出:
75
12、 JavaScript 中的閉包是什麼?
JavaScript 中的閉包意味着内部函數可以通路外部函數的變量——即使在外部函數傳回之後也是如此。
例如,要建立一個自增 1 的計數器,你可以使用閉包:
function createCounter() {
let counter = 0;
function increment() {
counter++;
console.log(counter);
}
return increment;
}
這裡 createCounter() 是外部函數, increment() 是内部函數。現在,你可以按如下方式使用它:
const add = createCounter();
add();
add();
add();
輸出:
1
2
3
這是有效的,因為存儲内部函數 increment() 的 add 仍然可以通路 createCounter() 函數的計數器變量。
這是可能的,因為 JavaScript 的閉包特性:即使在外部函數傳回之後,内部函數也可以通路外部函數的變量。
13、 JavaScript 中如何處理異常?
如果表達式抛出錯誤,你可以使用 try...catch 語句處理它們。
使用這個結構的想法是嘗試運作一個表達式,比如一個帶有輸入的函數,并捕獲可能的錯誤。
例如:
function weekDay(dayNum) {
if (dayNum < 1 || dayNum > 7) {
throw 'InvalidDayNumber'
} else {
return ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][dayNum - 1];
}
}
try { // Try to run the following
let day = weekDay(8);
console.log(day);
}
catch (e) { // catch an error if the above try failed
let day = 'unknown';
console.log(e);
}
14、 什麼是網絡存儲?
Web 存儲是一種 API,它為浏覽器提供了一種将鍵值對存儲到使用者浏覽器本地的方法。使用網絡存儲使這個過程比使用 cookie 更直覺。
Web 存儲提供了兩種存儲資料的方式:
本地存儲 - 為用戶端存儲沒有到期日期的資料。
會話存儲——隻存儲一個會話的資料。浏覽器關閉時資料消失。
以下是如何從 sessionStorage 儲存、通路和删除項目的示例:
// Save data to sessionStorage
sessionStorage.setItem('favoriteColor', 'gray');
// Get the color from the sessionStorage
let data = sessionStorage.getItem('favoriteColor');
console.log(data);
// Remove saved color preset from sessionStorage
sessionStorage.removeItem('favoriteColor');
// Remove ALL the saved data from sessionStorage
sessionStorage.clear();
以下是使用 localStorage 執行相同操作的方法:
// Save data to localStorage
localStorage.setItem('favoriteColor', 'gray');
// Get the color from the localStorage
let data = localStorage.getItem('favoriteColor');
console.log(data);
// Remove saved color preset from localStorage
localStorage.removeItem('favoriteColor');
// Remove ALL the saved data from localStorage
localStorage.clear();
15、為什麼需要網絡存儲?
Web 存儲(問題 14)可以在本地存儲大量資料。關鍵是它不會影響網站的性能。
使用網絡存儲,資訊不會存儲到伺服器中。與 cookie 相比,這使其成為更可取的方法。
16、什麼是子產品?
子產品是可重用代碼的單元。通常,你可以從子產品中将有用的函數或構造函數導入到你的項目中。
從子產品導入功能可能如下所示:
import { hello } from './modules/helloWorld.js';
17、JavaScript 中的“範圍”是什麼意思?
範圍定義了“代碼的可見性”。
更正式地說,作用域描述了代碼中可以通路變量、函數和其他對象的位置。範圍是在運作時在你的代碼中建立的。
例如,塊作用域表示花括号之間的“區域”:
if(true) {
let word = "Hello";
}
console.log(word); // ERROR OCCURS
在這裡,變量 word 不能從其他任何地方通路,但在 if 語句中。
18、JavaScript 中的高階函數是什麼?
一個高階函數對另一個函數進行操作。它要麼接受一個函數作為參數,要麼傳回另一個函數。
例如:
function runThis(inputFunction) {
inputFunction();
}
runThis(function() { console.log("Hello world") });
輸出:
Hello world
另外一個示例:
function giveFunction() {
return function() {
console.log("Hello world")
}
}
var action = giveFunction();
action()
輸出:
Hello world
19、 JavaScript 中的“this”關鍵字是什麼?
這是指對象本身。
例如:
var student = {
name: "Matt",
getName: function(){
console.log(this.name);
}
}
student.getName();
輸出:
Matt
要使 getName() 方法在 student 對象中工作,該對象必須通路自己的屬性。這可以通過對象内的 this 關鍵字實作。
20、call() 方法有什麼作用?
call() 方法可用于在另一個對象上調用一個對象的方法。
obj1.func.call(obj2)
例如:
var student = {
name: "Matt",
getName: function(){
console.log(this.name);
}
}
var anotherStudent = {
name: "Sophie"
};
student.getName.call(anotherStudent);
輸出:
Sofie
Call() 方法還可用于通過指定所有者對象來調用函數。
例如:
function sayHi(){
console.log("Hello " + this.name);
}
var person = {name: "Matt"};
sayHi.call(person);
輸出:
Hello Matt
call() 也可以接受參數。
例如:
function sayHi(adjective){
console.log("Hello " + this.name + ", You are " + adjective);
}
var obj = {name: "Matt"};
sayHi.call(obj, "awesome");
輸出:
Hello Matt, you are awesome
21、apply() 方法是什麼?
apply() 方法的作用與 call() 方法相同。不同之處在于 apply() 方法接受作為數組的參數。
例如:
const person = {
name: 'John'
}
function greet(greeting, message) {
return `${greeting} ${this.name}. ${message}`;
}
let result = greet.apply(person, ['Hello', 'How are you?']);
console.log(result);
輸出:
Hello John. How are you?
在行中:
let result = greet.apply(person, ['Hello', 'How are you?']);
在greet()函數中,‘Hello’被配置設定給greeting,‘How are you?’被配置設定給message。
22、什麼是bind()方法?
bind() 方法傳回一個新函數,其 this 已設定為另一個對象。
與 apply() 和 call() 不同,bind() 不會立即執行函數。相反,它傳回一個新版本的函數,其 this 被設定為另一個值。
讓我們看一個例子:
let person = {
name: 'John',
getName: function() {
console.log(this.name);
}
};
window.setTimeout(person.getName, 1000);
這不會列印名稱“John”,而是列印 undefined。要了解為什麼會發生這種情況,請以等效的方式重寫最後一行:
let func = person.getName;
setTimeout(func, 1000);
setTimeout() 與 person 對象分開接收函數,但沒有 person 的名字。是以,當 setTimeout() 調用 person.getName 時,名稱是未定義的。
要解決此問題,你需要将 getName() 方法綁定到 person 對象:
let func = person.getName.bind(person);
setTimeout(func, 1000);
輸出:
John
讓我們檢查一下這種方法是如何工作的:
person.getName 方法綁定到 person 對象。
綁定函數 func 現在将此值設定為 person 對象。當你将這個新綁定函數傳遞給 setTimeout() 函數時,它知道如何擷取此人的姓名。
23、什麼是柯裡化?
柯裡化意味着将具有 n 個參數的函數轉換為具有一個或更少參數的 n 個函數。
例如,假設你有一個将兩個數字相加的函數 add():
function add(a, b) {
return a + b;
}
你可以通過以下方式調用此函數:
add(2,3)
然後讓我們咖喱函數:
function add(a) {
return function(b) {
return a + b;
}
}
現在你可以通過以下方式調用這個柯裡化函數:
add(2)(3)
柯裡化不會改變函數的行為。它改變了它的調用方式。
24、JavaScript 中的 promise 是什麼?
承諾是一個可能在未來産生價值的對象。
承諾始終處于可能的狀态之一:已完成、拒絕或未決。
建立一個承諾看起來像這樣:
const promise = new Promise(function(resolve, reject) {
// implement the promise here
})
例如,讓我們建立一個在被調用後兩秒解析的承諾。
const promise = new Promise(resolve => {
setTimeout(() => {
resolve("Hello, world!");
}, 2000);
}, reject => {});
現在 promises 的關鍵是你可以在使用 .then() 方法解析 promise 後立即執行代碼:
promise.then(result => console.log(result));
輸出:
Hello, world!
Promise 可以連結在一起,這樣一個已解決的 Promise 會傳回一個新的 Promise。
下面是一個 promise 的流程圖,它也說明了如何連結它們:
25、為什麼要使用承諾?
在 JavaScript 中,promise 對異步操作很有用。
過去,必須使用回調來處理異步操作,即在操作完成後立即執行的函數。這導緻了“回調地獄”,一種帶有嵌套回調的金字塔形代碼。
Promises 通過減少回調地獄和編寫更幹淨的代碼為回調提供了另一種方法。這是可能的,因為 Promise 可以按以下方式連結:
26、JavaScript 中的回調函數是什麼?
回調函數是作為參數傳遞給另一個函數的函數。該函數在傳遞給它的函數内部執行,以在某些操作完成時“回調”。
讓我們看一個例子:
function greetName(name) {
console.log('Hello ' + name);
}
function askName(callback) {
let name = prompt('Enter your name.');
callback(name);
}
askName(greetName);
這段代碼會提示你一個名字,當你輸入名字時,它會對該名字說“你好”。是以回調函數(在本例中為 greetName)僅在您輸入名稱後執行。
27、為什麼在 JavaScript 中使用回調?
回調很有用,因為 JavaScript 是一種事件驅動的語言。換句話說,它不是等待響應,而是在偵聽其他事件的同時繼續執行。
上面的例子示範了 JavaScript 中回調的用處:
function greetName(name) {
console.log('Hello ' + name);
}
function askName(callback) {
let name = prompt('Enter your name.');
callback(name);
}
askName(greetName);
28、JavaScript 中的嚴格模式是什麼?
嚴格模式允許你設定程式在嚴格的上下文中運作。這可以防止執行某些操作。此外,還會引發更多異常。
表達“嚴格使用”;告訴浏覽器啟用嚴格模式。
例如:
"use strict";
number = 1000;
這會導緻錯誤,因為嚴格模式會阻止您為未聲明的變量指派。
29、 什麼是立即調用函數?
立即調用函數 (IIFE) 在定義後立即運作。
例如:
(function(){
// action here
})();
要了解 IIFE 的工作原理,請檢視它周圍的括号:
當 JavaScript 看到關鍵字 function 時,它假設有一個函數聲明即将到來。
但是上面的聲明是無效的,因為函數沒有名字。
為了解決這個問題,使用了聲明周圍的第一組括号。這告訴解釋器它是一個函數表達式,而不是一個聲明。
(function (){
// action here;
})
然後,要調用該函數,需要在函數聲明的末尾添加另一組括号。這類似于調用任何其他函數:
(function (){
// action here
})();
30、什麼是cookie?
cookie 是存儲在你計算機上的一個小資料包。
例如,網站可以在通路者的浏覽器上放置 cookie,以便在使用者下次通路該頁面時記住登入憑據。
在幕後,cookie 是帶有鍵值對的文本檔案。要建立、讀取或删除 cookie,請使用 document.cookie 屬性。
例如,讓我們建立一個儲存使用者名的 cookie:
document.cookie = "username=foobar123";
31、為什麼在 JavaScript 中使用嚴格模式?
嚴格模式有助于編寫“安全”的 JavaScript 代碼。這意味着糟糕的文法實踐會轉化為真正的錯誤。
例如,嚴格模式阻止建立全局變量。
要聲明嚴格模式,請添加“use strict”;在要在嚴格模式下的語句之前的語句:
'use strict';
const sentence = "Hello, this is very strict";
32、雙感歎号有什麼作用?
雙感歎号将 JavaScript 中的任何内容轉換為布爾值。
!!true // true
!!2 // true
!![] // true
!!"Test" // true
!!false // false
!!0 // false
!!"" // false
這是有效的,因為 JavaScript 中的任何東西本質上都是“真實的”或“虛假的”。
33、如何删除屬性及其值?
你可以使用 delete 關鍵字從對象中删除屬性及其值。
讓我們看一個例子:
var student = {name: "John", age:20};
delete student.age;
console.log(student);
輸出:
{name: "John"}
34、如何在 JavaScript 中檢查變量的類型?
使用 typeof 運算符。
typeof "John Abraham" // Returns "string"
typeof 100 // Returns "number"
35、JavaScript 中的 null 是什麼?
null 表示沒有值。它突出顯示變量不指向任何對象。
null 的類型是一個對象:
var name = null;
console.log(typeof(name))
36、Null vs undefined?
null:
- 是一個值,訓示變量不指向任何對象。
- 是對象類型。
- 表示 null、null或不存在的引用。
- 表示沒有變量值。
- 使用原始操作轉換為 0。
undefined:
- 是表示已聲明但沒有值的變量的值
- 是未定義的類型。
- 表示沒有變量。
- 使用原始操作轉換為 NaN。
37、你能用 JavaScript 通路曆史嗎?
對的,這是可能的。你可以通過包含浏覽器曆史記錄的 window.history 通路曆史記錄。
要檢索上一個和下一個 URL,請使用以下方法:
window.history.back()
window.history.forward()
38、什麼是全局變量?
全局變量在代碼中随處可見。
要建立全局變量,請省略 var 關鍵字:
x = 100; // Creates a global variable.
此外,如果你在任何函數之外使用 var 建立變量,你也将建立一個全局變量。
39、 JavaScript 與 Java 有關系嗎?
不。
它們是兩種不同的程式設計語言,彼此無關。
40、什麼是 JavaScript 事件?
事件是發生在 HTML 元素上的事情。在 HTML 頁面中使用 JavaScript 時,它可以對事件做出反應,例如按鈕單擊。
讓我們建立一個 HTML 頁面,其中有一個按鈕,當單擊該按鈕時,會顯示一個警報:
<!doctype html>
<html>
<head>
<script>
function sayHi() {
alert('Hi, how are you?');
}
</script>
</head>
<body>
<button type="button" onclick="sayHi()">Click here</button>
</body>
</html>
41、preventDefault() 方法有什麼作用?
preventDefault() 取消一個方法。名稱 preventDefault 很好地描述了行為。它可以防止事件采取預設行為。
例如,你可以在單擊送出按鈕時阻止表單送出:
document.getElementById("link").addEventListener("click", function(event){
event.preventDefault()
});
42、setTimeout() 方法是什麼?
setTimeout() 方法在指定的毫秒數後調用函數(一次)。例如,讓我們在一秒(1000 毫秒)後記錄一條消息:
setTimeout(function() {
console.log("Good day");
}, 1000);
43、setInterval() 方法是什麼?
setInterval() 方法以自定義間隔定期調用函數。
例如,讓我們每隔一秒定期記錄一條消息:
setInterval(function() {
console.log("Good day");
}, 1000);
44、什麼是ECMAScript?
ECMAScript 是構成 JavaScript 基礎的腳本語言。
ECMAScript 由 ECMA 國際标準組織标準化(檢視 ECMA-262 和 ECMA-402 規範)。
45、什麼是JSON?
JSON(JavaScript Object Notation)是一種用于交換資料的輕量級資料格式。
例如,這是一個 JSON 對象:
{
'name': 'Matt',
'address': 'Imaginary Road 22',
'age': 32,
'married': false,
'hobbies': ['Jogging', 'Tennis', 'Padel']
}
JSON 的文法規則是:
- 資料以鍵值對的形式存在。
- 資料以逗号分隔。
- 花括号定義一個對象。
- 方括号定義了一個數組。
46、 JSON 用在什麼地方?
當向伺服器發送資料時,反之亦然,資料必須是文本格式。
JSON 是一種純文字格式,允許将資料發送到伺服器,并将資料從伺服器發送到浏覽器。幾乎所有程式設計語言都支援 JSON,是以它也可以與其他語言一起使用。
47、為什麼要使用 JSON 字元串化?
當你向伺服器發送資料時,它必須是一個字元串。
要将 JavaScript 對象轉換為字元串,你可以使用 JSON.stringify() 方法。
var dataJSON = {name: "Matt", age: 51};
var dataString = JSON.stringify(dataJSON);
console.log(dataString);
輸出:
'{"name":"Matt","age":51}'
48、 如何将 JSON 字元串轉換為 JSON 對象?
當你從伺服器接收資料時,它始終是字元串格式。要将 JSON 字元串轉換為 JavaScript 對象,請使用 JSON.parse() 方法。
var data = '{"name":"Matt", "age":51}';
var dataJSON = JSON.parse(data);
console.log(dataJSON);
輸出:
{
name:"Matt",
age:51
}
49、如何為變量配置設定預設值?
使用邏輯運算符 || 在指派中提供一個預設值。
const a = b || c;
這樣一來,如果 b 為假,那麼 c 将被配置設定給 a。 (Falsy 表示 null、false、undefined、0、空字元串或 NaN。)
50、 你能為函數定義屬性嗎?
是的,因為函數也是對象。
讓我們看一個例子:
let func = function(x) {
};
func.property1 = "Hello there";
console.log(func.property1);
輸出:
Hello there
PS:因為文章篇幅關系,今天先分享前面50道面試題,剩下的50道題目放在下篇裡,敬請繼續關注。
學習更多技能
請點選下方公衆号
、