50道JavaScript高頻面試題及答案總結(jié)大全
一、基礎(chǔ)概念與數(shù)據(jù)類型
1. JavaScript 有哪些數(shù)據(jù)類型?
答案:
基本類型:String、Number、Boolean、null、undefined、Symbol(ES6)、BigInt(ES2020)
引用類型:Object(包括 Array、Function、Date、RegExp 等)
2. null 和 undefined 的區(qū)別?
答案:
undefined:變量已聲明但未賦值
null:表示空值,是一個可以賦給變量的特殊值
typeof null 返回 “object”,這是歷史遺留 bug
3. == 和 === 的區(qū)別?
答案:
==:寬松相等,會進行類型轉(zhuǎn)換
===:嚴(yán)格相等,不會進行類型轉(zhuǎn)換
1 == '1' // true 1 === '1' // false
4. 什么是變量提升?
答案:
var 聲明的變量會提升到作用域頂部
只有聲明會提升,賦值不會提升
let 和 const 存在暫時性死區(qū),不會提升
5. let、const、var 的區(qū)別?

6. 什么是作用域鏈?
答案:
函數(shù)在查找變量時,先從自身作用域查找
找不到則向父級作用域查找,直到全局作用域
這種鏈?zhǔn)讲檎谊P(guān)系稱為作用域鏈
7. 什么是閉包?
答案:
函數(shù)嵌套函數(shù),內(nèi)部函數(shù)可以訪問外部函數(shù)的變量
外部函數(shù)執(zhí)行完畢后,其變量仍然被內(nèi)部函數(shù)引用
常見用途:私有變量、函數(shù)工廠、模塊模式
8. 閉包的優(yōu)缺點?
答案:
優(yōu)點:
創(chuàng)建私有變量和方法
實現(xiàn)函數(shù)柯里化
模塊化開發(fā)
缺點:
內(nèi)存泄漏(如果閉包引用不被釋放)
性能考慮(每次創(chuàng)建函數(shù)都會創(chuàng)建閉包)
9. 解釋詞法作用域?
答案:
JavaScript 采用詞法作用域(靜態(tài)作用域)
作用域在函數(shù)定義時就確定了,而不是調(diào)用時
與動態(tài)作用域相對
二、原型與繼承
10. 什么是原型鏈?
答案:
每個對象都有 __proto__ 屬性,指向其構(gòu)造函數(shù)的 prototype
prototype 也是對象,也有 __proto__,形成鏈?zhǔn)浇Y(jié)構(gòu)
查找屬性時,沿著原型鏈向上查找
11. 如何實現(xiàn)繼承?
答案:
原型鏈繼承:
function Parent() {}
function Child() {}
Child.prototype = new Parent()
構(gòu)造函數(shù)繼承:
function Child() {
Parent.call(this)
}
組合繼承(最常用):
function Child() {
Parent.call(this)
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
Class 繼承(ES6):
class Child extends Parent {
constructor() {
super()
}
}
12. new 操作符做了什么?
答案:
創(chuàng)建一個空對象
將空對象的 __proto__ 指向構(gòu)造函數(shù)的 prototype
將 this 指向這個空對象
執(zhí)行構(gòu)造函數(shù)
如果構(gòu)造函數(shù)返回對象則返回該對象,否則返回新對象
13. instanceof 的原理?
答案:
檢查右邊構(gòu)造函數(shù)的 prototype 是否在左邊對象的原型鏈上
實現(xiàn)原理:
function myInstanceof(left, right) {
let proto = Object.getPrototypeOf(left)
while (true) {
if (proto === null) return false
if (proto === right.prototype) return true
proto = Object.getPrototypeOf(proto)
}
}
三、函數(shù)與 this
14. 解釋 this 的指向?
答案:
普通函數(shù)調(diào)用:this 指向全局對象(嚴(yán)格模式下為 undefined)
方法調(diào)用:this 指向調(diào)用該方法的對象
構(gòu)造函數(shù)調(diào)用:this 指向新創(chuàng)建的實例
call/apply/bind 調(diào)用:this 指向第一個參數(shù)
箭頭函數(shù):this 指向定義時的上下文,不會改變
15. call、apply、bind 的區(qū)別?
答案:
func.call(thisArg, arg1, arg2, ...) // 參數(shù)逐個傳遞 func.apply(thisArg, [argsArray]) // 參數(shù)作為數(shù)組傳遞 func.bind(thisArg, arg1, arg2, ...) // 返回新函數(shù),不立即執(zhí)行
16. 箭頭函數(shù)與普通函數(shù)的區(qū)別?
答案:
箭頭函數(shù)沒有自己的 this,繼承外層
箭頭函數(shù)沒有 arguments 對象
箭頭函數(shù)不能作為構(gòu)造函數(shù)(不能用 new)
箭頭函數(shù)沒有 prototype 屬性
箭頭函數(shù)不能使用 yield,不能用作生成器
17. 什么是高階函數(shù)?
答案:
接受函數(shù)作為參數(shù)
或返回一個函數(shù)
例如:map、filter、reduce、bind
異步編程
18. 什么是事件循環(huán)?
答案:
JavaScript 是單線程的,通過事件循環(huán)處理異步
任務(wù)分為宏任務(wù)和微任務(wù)
執(zhí)行順序:同步代碼 → 微任務(wù) → 宏任務(wù)
宏任務(wù):setTimeout、setInterval、I/O
微任務(wù):Promise.then、process.nextTick、MutationObserver
19. Promise 的狀態(tài)?
答案:
pending:初始狀態(tài)
fulfilled:操作成功完成
rejected:操作失敗
狀態(tài)一旦改變就不會再變
20. Promise 的常用方法?
答案:
Promise.resolve(value) // 返回 resolved 狀態(tài)的 Promise Promise.reject(reason) // 返回 rejected 狀態(tài)的 Promise Promise.all(iterable) // 所有成功才成功,一個失敗就失敗 Promise.race(iterable) // 第一個改變狀態(tài)的 Promise 決定結(jié)果 Promise.allSettled(iterable) // 所有 Promise 都完成后返回結(jié)果數(shù)組
21. async/await 的優(yōu)點?
答案:
代碼更簡潔,類似同步寫法
更好的錯誤處理(可以使用 try-catch)
更容易調(diào)試
避免回調(diào)地獄
22. 實現(xiàn)一個 Promise?
答案:
class MyPromise {
constructor(executor) {
this.state = 'pending'
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
}
}
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = reason
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
// 簡化實現(xiàn),實際更復(fù)雜
if (this.state === 'fulfilled') {
onFulfilled(this.value)
}
if (this.state === 'rejected') {
onRejected(this.reason)
}
}
}
四、ES6+ 新特性
23. 解構(gòu)賦值的用途?
答案:
// 數(shù)組解構(gòu)
const [a, b] = [1, 2]
// 對象解構(gòu)
const { name, age } = { name: 'John', age: 30 }
// 函數(shù)參數(shù)解構(gòu)
function foo({ x, y }) { return x + y }
// 交換變量
[a, b] = [b, a]
24. 擴展運算符的用途?
答案:
// 復(fù)制數(shù)組
const arr2 = [...arr1]
// 合并數(shù)組
const arr3 = [...arr1, ...arr2]
// 函數(shù)參數(shù)
Math.max(...numbers)
// 對象淺拷貝
const obj2 = { ...obj1 }
25. 模板字符串的特性?
答案:
// 支持換行
const str = `第一行
第二行`
// 支持表達(dá)式
const name = 'John'
const greeting = `Hello, ${name}!`
// 標(biāo)簽?zāi)0?
function tag(strings, ...values) {
// strings: 模板字符串的靜態(tài)部分
// values: 表達(dá)式的值
}
26. Symbol 的作用?
答案:
創(chuàng)建唯一的值,避免屬性名沖突
可用作對象的私有屬性
內(nèi)置 Symbol 值如 Symbol.iterator、Symbol.toStringTag
27. Set 和 Map 的區(qū)別?
答案:
Set:值的集合,值唯一
Map:鍵值對的集合,鍵可以是任意類型
WeakSet:弱引用集合,只能存對象
WeakMap:弱引用鍵值對,鍵只能是對象
五、DOM 與 BOM
28. 事件委托是什么?
答案:
將事件監(jiān)聽器綁定到父元素
利用事件冒泡機制處理子元素事件
優(yōu)點:減少內(nèi)存消耗,動態(tài)元素也能處理
29. 事件冒泡和事件捕獲?
答案:
事件冒泡:從目標(biāo)元素向上傳播到根元素
事件捕獲:從根元素向下傳播到目標(biāo)元素
DOM 事件流:捕獲 → 目標(biāo) → 冒泡
addEventListener 第三個參數(shù)控制階段
30. 阻止事件默認(rèn)行為和冒泡?
答案:
event.preventDefault() // 阻止默認(rèn)行為 event.stopPropagation() // 阻止冒泡 event.stopImmediatePropagation() // 阻止同一事件的其他監(jiān)聽器
六、性能與安全
31. 什么是防抖和節(jié)流?
答案:
防抖:事件觸發(fā)后延遲執(zhí)行,如果期間再次觸發(fā)則重新計時
節(jié)流:在一定時間內(nèi)只執(zhí)行一次
// 防抖
function debounce(fn, delay) {
let timer
return function(...args) {
clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, args), delay)
}
}
// 節(jié)流
function throttle(fn, delay) {
let lastTime = 0
return function(...args) {
const now = Date.now()
if (now - lastTime >= delay) {
fn.apply(this, args)
lastTime = now
}
}
}
32. 什么是跨域?如何解決?
答案:
瀏覽器同源策略限制
解決方案:
JSONP(僅 GET 請求) CORS(服務(wù)器設(shè)置響應(yīng)頭) 代理服務(wù)器 postMessage WebSocket
33. 什么是 XSS 攻擊?如何防范?
答案:
跨站腳本攻擊,注入惡意腳本
防范措施:
輸入過濾和轉(zhuǎn)義
設(shè)置 HttpOnly Cookie
使用 CSP(內(nèi)容安全策略)
避免內(nèi)聯(lián)事件處理
34. 什么是 CSRF 攻擊?如何防范?
答案:
跨站請求偽造,誘導(dǎo)用戶發(fā)送惡意請求
防范措施:
使用 CSRF Token
驗證 Referer 頭
設(shè)置 SameSite Cookie
驗證碼
七、算法與數(shù)據(jù)結(jié)構(gòu)
35. 數(shù)組去重的方法?
答案:
// 1. Set [...new Set(array)] // 2. filter + indexOf array.filter((item, index) => array.indexOf(item) === index) // 3. reduce array.reduce((acc, cur) => acc.includes(cur) ? acc : [...acc, cur], [])
36. 數(shù)組扁平化的方法?
答案:
// 1. flat
arr.flat(Infinity)
// 2. reduce + 遞歸
function flatten(arr) {
return arr.reduce((acc, cur) =>
Array.isArray(cur)
? acc.concat(flatten(cur))
: acc.concat(cur),
[])
}
// 3. toString(僅限數(shù)字?jǐn)?shù)組)
arr.toString().split(',').map(Number)
37. 深拷貝的實現(xiàn)?
答案:
function deepClone(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj
if (map.has(obj)) return map.get(obj)
const clone = Array.isArray(obj) ? [] : {}
map.set(obj, clone)
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], map)
}
}
return clone
}
八、 瀏覽器相關(guān)
38. 從輸入 URL 到頁面顯示的過程?
答案:
DNS 解析
TCP 連接
發(fā)送 HTTP 請求
服務(wù)器處理請求并返回響應(yīng)
瀏覽器解析渲染
連接結(jié)束
39. 重排和重繪?
答案:
重排:布局改變,需要重新計算
重繪:外觀改變,不需要重新布局
優(yōu)化:避免頻繁操作 DOM,使用 transform 和 opacity
40. 內(nèi)存泄漏的原因?
答案:
意外的全局變量
未清理的定時器
閉包濫用
未解綁的事件監(jiān)聽
DOM 引用未清除
九、模塊化
41. CommonJS 和 ES6 Module 的區(qū)別?

42. AMD 和 CMD 的區(qū)別?
答案:
AMD:異步加載,提前執(zhí)行(RequireJS)
CMD:異步加載,延遲執(zhí)行(SeaJS)
現(xiàn)在多用 ES6 Module
其他重要概念
43. 什么是柯里化?
答案:
將多參數(shù)函數(shù)轉(zhuǎn)化為單參數(shù)函數(shù)序列
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args)
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2))
}
}
}
}
44. 什么是函數(shù)組合?
答案:
將多個函數(shù)組合成一個新函數(shù)
function compose(...fns) {
return function(x) {
return fns.reduceRight((acc, fn) => fn(acc), x)
}
}
45. 什么是尾調(diào)用優(yōu)化?
答案:
函數(shù)最后一步調(diào)用另一個函數(shù)
ES6 嚴(yán)格模式下支持
可以優(yōu)化遞歸性能
46. Generator 函數(shù)的作用?
答案:
可以暫停執(zhí)行和恢復(fù)執(zhí)行
配合 yield 使用
常用于異步編程(async/await 的基礎(chǔ))
function* gen() {
yield 1
yield 2
return 3
}
47. Proxy 和 Reflect?
答案:
Proxy:代理對象,攔截操作
Reflect:操作對象的 API,與 Proxy 對應(yīng)
const proxy = new Proxy(target, {
get(target, prop) {
return Reflect.get(target, prop)
}
})
48. WeakMap 和 WeakSet 的特點?
答案:
弱引用,不影響垃圾回收
鍵/值必須是對象
不可遍歷
沒有 size 屬性
49. 什么是 Optional Chaining?
答案:
ES2020 新增,可選鏈操作符 ?.
避免訪問嵌套對象時的空值錯誤
const name = obj?.user?.name
50. 什么是 Nullish Coalescing?
答案:
ES2020 新增,空值合并操作符 ??
僅在左側(cè)為 null 或 undefined 時返回右側(cè)
const value = a ?? 'default'
總結(jié)
到此這篇關(guān)于50道JavaScript高頻面試題及答案總結(jié)大全的文章就介紹到這了,更多相關(guān)js高頻面試題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript函數(shù)式編程實現(xiàn)介紹
函數(shù)式編程是一種編程范式,將整個程序都由函數(shù)調(diào)用以及函數(shù)組合構(gòu)成。 可以看成一條流水線,數(shù)據(jù)可以不斷地從一個函數(shù)的輸出流入另一個函數(shù)的輸入,最后輸出結(jié)果2022-09-09
用Fundebug插件記錄網(wǎng)絡(luò)請求異常的方法
這篇文章主要介紹了用Fundebug插件記錄網(wǎng)絡(luò)請求異常的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-02-02
JS數(shù)組進階示例【數(shù)組的幾種函數(shù)用法】
這篇文章主要介紹了JS數(shù)組進階,結(jié)合實例形式總結(jié)分析了數(shù)組的幾種常見函數(shù)基本用法,涉及JavaScript數(shù)組元素刪除、拼接、添加、倒序排列等相關(guān)操作技巧,需要的朋友可以參考下2020-01-01
js圖片滾動效果時間可隨意設(shè)定當(dāng)鼠標(biāo)移上去時停止
這篇文章主要介紹了js圖片滾動效果時間可隨意設(shè)定當(dāng)鼠標(biāo)移上去時停止,需要的朋友可以參考下2014-06-06
獲取offsetTop和offsetLeft值的js代碼(兼容)
offsetTop和offsetLeft的值在某些特殊的情況下是會使用到的,為了實現(xiàn)值的準(zhǔn)確獲取,本文采用js代碼實現(xiàn)下,有需求的朋友可以參考下哈2013-04-04
一文詳解JavaScript?如何將?HTML?轉(zhuǎn)成?Markdown
這篇文章主要介紹了一文詳解JavaScript如何將HTML轉(zhuǎn)成Markdown,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08
微信小程序wx.previewImage預(yù)覽圖片實例詳解
下面通過實例代碼給大家講解了微信小程序wx.previewImage預(yù)覽圖片功能,需要的朋友可以參考下2017-12-12

