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:表示空值,是一個(gè)可以賦給變量的特殊值
typeof null 返回 “object”,這是歷史遺留 bug
3. == 和 === 的區(qū)別?
答案:
==:寬松相等,會(huì)進(jìn)行類型轉(zhuǎn)換
===:嚴(yán)格相等,不會(huì)進(jìn)行類型轉(zhuǎn)換
1 == '1' // true 1 === '1' // false
4. 什么是變量提升?
答案:
var 聲明的變量會(huì)提升到作用域頂部
只有聲明會(huì)提升,賦值不會(huì)提升
let 和 const 存在暫時(shí)性死區(qū),不會(huì)提升
5. let、const、var 的區(qū)別?

6. 什么是作用域鏈?
答案:
函數(shù)在查找變量時(shí),先從自身作用域查找
找不到則向父級作用域查找,直到全局作用域
這種鏈?zhǔn)讲檎谊P(guān)系稱為作用域鏈
7. 什么是閉包?
答案:
函數(shù)嵌套函數(shù),內(nèi)部函數(shù)可以訪問外部函數(shù)的變量
外部函數(shù)執(zhí)行完畢后,其變量仍然被內(nèi)部函數(shù)引用
常見用途:私有變量、函數(shù)工廠、模塊模式
8. 閉包的優(yōu)缺點(diǎn)?
答案:
優(yōu)點(diǎn):
創(chuàng)建私有變量和方法
實(shí)現(xiàn)函數(shù)柯里化
模塊化開發(fā)
缺點(diǎn):
內(nèi)存泄漏(如果閉包引用不被釋放)
性能考慮(每次創(chuàng)建函數(shù)都會(huì)創(chuàng)建閉包)
9. 解釋詞法作用域?
答案:
JavaScript 采用詞法作用域(靜態(tài)作用域)
作用域在函數(shù)定義時(shí)就確定了,而不是調(diào)用時(shí)
與動(dòng)態(tài)作用域相對
二、原型與繼承
10. 什么是原型鏈?
答案:
每個(gè)對象都有 __proto__ 屬性,指向其構(gòu)造函數(shù)的 prototype
prototype 也是對象,也有 __proto__,形成鏈?zhǔn)浇Y(jié)構(gòu)
查找屬性時(shí),沿著原型鏈向上查找
11. 如何實(shí)現(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)建一個(gè)空對象
將空對象的 __proto__ 指向構(gòu)造函數(shù)的 prototype
將 this 指向這個(gè)空對象
執(zhí)行構(gòu)造函數(shù)
如果構(gòu)造函數(shù)返回對象則返回該對象,否則返回新對象
13. instanceof 的原理?
答案:
檢查右邊構(gòu)造函數(shù)的 prototype 是否在左邊對象的原型鏈上
實(shí)現(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)建的實(shí)例
call/apply/bind 調(diào)用:this 指向第一個(gè)參數(shù)
箭頭函數(shù):this 指向定義時(shí)的上下文,不會(huì)改變
15. call、apply、bind 的區(qū)別?
答案:
func.call(thisArg, arg1, arg2, ...) // 參數(shù)逐個(gè)傳遞 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ù)
或返回一個(gè)函數(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)一旦改變就不會(huì)再變
20. Promise 的常用方法?
答案:
Promise.resolve(value) // 返回 resolved 狀態(tài)的 Promise Promise.reject(reason) // 返回 rejected 狀態(tài)的 Promise Promise.all(iterable) // 所有成功才成功,一個(gè)失敗就失敗 Promise.race(iterable) // 第一個(gè)改變狀態(tài)的 Promise 決定結(jié)果 Promise.allSettled(iterable) // 所有 Promise 都完成后返回結(jié)果數(shù)組
21. async/await 的優(yōu)點(diǎn)?
答案:
代碼更簡潔,類似同步寫法
更好的錯(cuò)誤處理(可以使用 try-catch)
更容易調(diào)試
避免回調(diào)地獄
22. 實(shí)現(xiàn)一個(gè) 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) {
// 簡化實(shí)現(xiàn),實(shí)際更復(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. 擴(kuò)展運(yùn)算符的用途?
答案:
// 復(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)聽器綁定到父元素
利用事件冒泡機(jī)制處理子元素事件
優(yōu)點(diǎn):減少內(nèi)存消耗,動(dòng)態(tài)元素也能處理
29. 事件冒泡和事件捕獲?
答案:
事件冒泡:從目標(biāo)元素向上傳播到根元素
事件捕獲:從根元素向下傳播到目標(biāo)元素
DOM 事件流:捕獲 → 目標(biāo) → 冒泡
addEventListener 第三個(gè)參數(shù)控制階段
30. 阻止事件默認(rèn)行為和冒泡?
答案:
event.preventDefault() // 阻止默認(rèn)行為 event.stopPropagation() // 阻止冒泡 event.stopImmediatePropagation() // 阻止同一事件的其他監(jiān)聽器
六、性能與安全
31. 什么是防抖和節(jié)流?
答案:
防抖:事件觸發(fā)后延遲執(zhí)行,如果期間再次觸發(fā)則重新計(jì)時(shí)
節(jié)流:在一定時(shí)間內(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
驗(yàn)證 Referer 頭
設(shè)置 SameSite Cookie
驗(yàn)證碼
七、算法與數(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. 深拷貝的實(shí)現(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. 重排和重繪?
答案:
重排:布局改變,需要重新計(jì)算
重繪:外觀改變,不需要重新布局
優(yōu)化:避免頻繁操作 DOM,使用 transform 和 opacity
40. 內(nèi)存泄漏的原因?
答案:
意外的全局變量
未清理的定時(shí)器
閉包濫用
未解綁的事件監(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ù)組合?
答案:
將多個(gè)函數(shù)組合成一個(gè)新函數(shù)
function compose(...fns) {
return function(x) {
return fns.reduceRight((acc, fn) => fn(acc), x)
}
}
45. 什么是尾調(diào)用優(yōu)化?
答案:
函數(shù)最后一步調(diào)用另一個(gè)函數(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 的特點(diǎn)?
答案:
弱引用,不影響垃圾回收
鍵/值必須是對象
不可遍歷
沒有 size 屬性
49. 什么是 Optional Chaining?
答案:
ES2020 新增,可選鏈操作符 ?.
避免訪問嵌套對象時(shí)的空值錯(cuò)誤
const name = obj?.user?.name
50. 什么是 Nullish Coalescing?
答案:
ES2020 新增,空值合并操作符 ??
僅在左側(cè)為 null 或 undefined 時(shí)返回右側(cè)
const value = a ?? 'default'
總結(jié)
到此這篇關(guān)于50道JavaScript高頻面試題及答案總結(jié)大全的文章就介紹到這了,更多相關(guān)js高頻面試題內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Axios?get?post請求傳遞參數(shù)的實(shí)現(xiàn)代碼
axios是基于promise用于瀏覽器和node.js的http客戶端,支持瀏覽器和node.js,能攔截請求和響應(yīng),這篇文章主要介紹了axios?get?post請求傳遞參數(shù)的操作代碼,需要的朋友可以參考下2022-11-11
JavaScript實(shí)現(xiàn)控制并發(fā)請求的方法詳解
這篇文章主要為大家詳細(xì)介紹了如果有100個(gè)請求,那么如何使用JavaScript實(shí)現(xiàn)控制并發(fā)請求,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一2024-03-03
js當(dāng)一個(gè)變量為函數(shù)時(shí) 應(yīng)該注意的一點(diǎn)細(xì)節(jié)小結(jié)
變量testFun為一個(gè)匿名函數(shù),匿名函數(shù)返回的一個(gè)testFun.init對象(也是一個(gè)匿名函數(shù))2011-12-12
根據(jù)判斷瀏覽器類型屏幕分辨率自動(dòng)調(diào)用不同CSS的代碼
根據(jù)判斷瀏覽器類型屏幕分辨率自動(dòng)調(diào)用不同CSS的代碼...2007-02-02
8個(gè)鮮為人知但很實(shí)用的Web?API用法總結(jié)
在?Web?API?中,有非常有用的對象、屬性和函數(shù)可用于執(zhí)行小到訪問?DOM?這樣的小任務(wù),大到處理音頻、視頻這樣的復(fù)雜任務(wù)。下面就帶大家一起來看看一些不常見但很實(shí)用的Web?API的用法2022-08-08
判斷是否安裝flash player及當(dāng)前版本的JS代碼
本文為大家講述下如何使用jsJS判斷是否安裝flash player及版本,下面的處理代碼或許對大家有所幫助,感興趣的朋友可以參考下,希望對大家有所幫助2013-08-08

