无为而我 發表於 2026-1-11 10:31:13

50道JavaScript高频面试题及答案总结大全

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">一、基础概念与数据类型</a></li><ul class="second_class_ul"><li><a href="#_lab2_0_0">1. JavaScript 有哪些数据类型?</a></li><li><a href="#_lab2_0_1">2. null 和 undefined 的区别?</a></li><li><a href="#_lab2_0_2">3. == 和 === 的区别?</a></li><li><a href="#_lab2_0_3">4. 什么是变量提升?</a></li><li><a href="#_lab2_0_4">5. let、const、var 的区别?</a></li><li><a href="#_lab2_0_5">6. 什么是作用域链?</a></li><li><a href="#_lab2_0_6">7. 什么是闭包?</a></li><li><a href="#_lab2_0_7">8. 闭包的优缺点?</a></li><li><a href="#_lab2_0_8">9. 解释词法作用域?</a></li></ul><li><a href="#_label1">二、原型与继承</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_9">10. 什么是原型链?</a></li><li><a href="#_lab2_1_10">11. 如何实现继承?</a></li><li><a href="#_lab2_1_11">12. new 操作符做了什么?</a></li><li><a href="#_lab2_1_12">13. instanceof 的原理?</a></li></ul><li><a href="#_label2">三、函数与 this</a></li><ul class="second_class_ul"><li><a href="#_lab2_2_13">14. 解释 this 的指向?</a></li><li><a href="#_lab2_2_14">15. call、apply、bind 的区别?</a></li><li><a href="#_lab2_2_15">16. 箭头函数与普通函数的区别?</a></li><li><a href="#_lab2_2_16">17. 什么是高阶函数?</a></li><li><a href="#_lab2_2_17">18. 什么是事件循环?</a></li><li><a href="#_lab2_2_18">19. Promise 的状态?</a></li><li><a href="#_lab2_2_19">20. Promise 的常用方法?</a></li><li><a href="#_lab2_2_20">21. async/await 的优点?</a></li><li><a href="#_lab2_2_21">22. 实现一个 Promise?</a></li></ul><li><a href="#_label3">四、ES6+ 新特性</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_22">23. 解构赋值的用途?</a></li><li><a href="#_lab2_3_23">24. 扩展运算符的用途?</a></li><li><a href="#_lab2_3_24">25. 模板字符串的特性?</a></li><li><a href="#_lab2_3_25">26. Symbol 的作用?</a></li><li><a href="#_lab2_3_26">27. Set 和 Map 的区别?</a></li></ul><li><a href="#_label4">五、DOM 与 BOM</a></li><ul class="second_class_ul"><li><a href="#_lab2_4_27">28. 事件委托是什么?</a></li><li><a href="#_lab2_4_28">29. 事件冒泡和事件捕获?</a></li><li><a href="#_lab2_4_29">30. 阻止事件默认行为和冒泡?</a></li></ul><li><a href="#_label5">六、性能与安全</a></li><ul class="second_class_ul"><li><a href="#_lab2_5_30">31. 什么是防抖和节流?</a></li><li><a href="#_lab2_5_31">32. 什么是跨域?如何解决?</a></li><li><a href="#_lab2_5_32">33. 什么是 XSS 攻击?如何防范?</a></li><li><a href="#_lab2_5_33">34. 什么是 CSRF 攻击?如何防范?</a></li></ul><li><a href="#_label6">七、算法与数据结构</a></li><ul class="second_class_ul"><li><a href="#_lab2_6_34">35. 数组去重的方法?</a></li><li><a href="#_lab2_6_35">36. 数组扁平化的方法?</a></li><li><a href="#_lab2_6_36">37. 深拷贝的实现?</a></li></ul><li><a href="#_label7">八、 浏览器相关</a></li><ul class="second_class_ul"><li><a href="#_lab2_7_37">38. 从输入 URL 到页面显示的过程?</a></li><li><a href="#_lab2_7_38">39. 重排和重绘?</a></li><li><a href="#_lab2_7_39">40. 内存泄漏的原因?</a></li></ul><li><a href="#_label8">九、模块化</a></li><ul class="second_class_ul"><li><a href="#_lab2_8_40">41. CommonJS 和 ES6 Module 的区别?</a></li><li><a href="#_lab2_8_41">42. AMD 和 CMD 的区别?</a></li><li><a href="#_lab2_8_42">43. 什么是柯里化?</a></li><li><a href="#_lab2_8_43">44. 什么是函数组合?</a></li><li><a href="#_lab2_8_44">45. 什么是尾调用优化?</a></li><li><a href="#_lab2_8_45">46. Generator 函数的作用?</a></li><li><a href="#_lab2_8_46">47. Proxy 和 Reflect?</a></li><li><a href="#_lab2_8_47">48. WeakMap 和 WeakSet 的特点?</a></li><li><a href="#_lab2_8_48">49. 什么是 Optional Chaining?</a></li><li><a href="#_lab2_8_49">50. 什么是 Nullish Coalescing?</a></li></ul><li><a href="#_label9">总结&nbsp;</a></li><ul class="second_class_ul"></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>一、基础概念与数据类型</h2>
<p class="maodian"><a name="_lab2_0_0"></a></p><h3>1. JavaScript 有哪些数据类型?</h3>
<p>答案:</p>
<p>基本类型:String、Number、Boolean、null、undefined、Symbol(ES6)、BigInt(ES2020)</p>
<p>引用类型:Object(包括 Array、Function、Date、RegExp 等)</p>
<p class="maodian"><a name="_lab2_0_1"></a></p><h3>2. null 和 undefined 的区别?</h3>
<p>答案:</p>
<p>undefined:变量已声明但未赋值</p>
<p>null:表示空值,是一个可以赋给变量的特殊值</p>
<p>typeof null 返回 &ldquo;object&rdquo;,这是历史遗留 bug</p>
<p class="maodian"><a name="_lab2_0_2"></a></p><h3>3. == 和 === 的区别?</h3>
<p>答案:</p>
<p>==:宽松相等,会进行类型转换</p>
<p>===:严格相等,不会进行类型转换</p>
<div class="jb51code"><pre class="brush:js;">1 == '1'// true
1 === '1' // false
</pre></div>
<p class="maodian"><a name="_lab2_0_3"></a></p><h3>4. 什么是变量提升?</h3>
<p>答案:</p>
<p>var 声明的变量会提升到作用域顶部</p>
<p>只有声明会提升,赋值不会提升</p>
<p>let 和 const 存在暂时性死区,不会提升</p>
<p class="maodian"><a name="_lab2_0_4"></a></p><h3>5. let、const、var 的区别?</h3>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026011110263323.png" /></p>
<p class="maodian"><a name="_lab2_0_5"></a></p><h3>6. 什么是作用域链?</h3>
<p>答案:</p>
<p>函数在查找变量时,先从自身作用域查找</p>
<p>找不到则向父级作用域查找,直到全局作用域</p>
<p>这种链式查找关系称为作用域链</p>
<p class="maodian"><a name="_lab2_0_6"></a></p><h3>7. 什么是闭包?</h3>
<p>答案:</p>
<p>函数嵌套函数,内部函数可以访问外部函数的变量</p>
<p>外部函数执行完毕后,其变量仍然被内部函数引用</p>
<p>常见用途:私有变量、函数工厂、模块模式</p>
<p class="maodian"><a name="_lab2_0_7"></a></p><h3>8. 闭包的优缺点?</h3>
<p>答案:<br /><strong>优点</strong>:</p>
<p>创建私有变量和方法</p>
<p>实现函数柯里化</p>
<p>模块化开发</p>
<p><strong>缺点</strong>:</p>
<p>内存泄漏(如果闭包引用不被释放)</p>
<p>性能考虑(每次创建函数都会创建闭包)</p>
<p class="maodian"><a name="_lab2_0_8"></a></p><h3>9. 解释词法作用域?</h3>
<p>答案:</p>
<p>JavaScript 采用词法作用域(静态作用域)</p>
<p>作用域在函数定义时就确定了,而不是调用时</p>
<p>与动态作用域相对</p>
<p class="maodian"><a name="_label1"></a></p><h2>二、原型与继承</h2>
<p class="maodian"><a name="_lab2_1_9"></a></p><h3>10. 什么是原型链?</h3>
<p>答案:</p>
<p>每个对象都有 <code>__proto__</code> 属性,指向其构造函数的 <code>prototype</code></p>
<p><code>prototype</code> 也是对象,也有 <code>__proto__</code>,形成链式结构</p>
<p>查找属性时,沿着原型链向上查找</p>
<p class="maodian"><a name="_lab2_1_10"></a></p><h3>11. 如何实现继承?</h3>
<p>答案:</p>
<p><strong>原型链继承</strong>:</p>
<div class="jb51code"><pre class="brush:js;">function Parent() {}
function Child() {}
Child.prototype = new Parent()
</pre></div>
<p><strong>构造函数继承</strong>:</p>
<div class="jb51code"><pre class="brush:js;">function Child() {
    Parent.call(this)
}
</pre></div>
<p><strong>组合继承(最常用)</strong>:</p>
<div class="jb51code"><pre class="brush:js;">function Child() {
    Parent.call(this)
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
</pre></div>
<p><strong>Class 继承(ES6)</strong>:</p>
<div class="jb51code"><pre class="brush:js;">class Child extends Parent {
    constructor() {
      super()
    }
}
</pre></div>
<p class="maodian"><a name="_lab2_1_11"></a></p><h3>12. new 操作符做了什么?</h3>
<p>答案:</p>
<p>创建一个空对象</p>
<p>将空对象的 <code>__proto__</code> 指向构造函数的 <code>prototype</code></p>
<p>将 this 指向这个空对象</p>
<p>执行构造函数</p>
<p>如果构造函数返回对象则返回该对象,否则返回新对象</p>
<p class="maodian"><a name="_lab2_1_12"></a></p><h3>13. instanceof 的原理?</h3>
<p>答案:</p>
<p>检查右边构造函数的 <code>prototype</code> 是否在左边对象的原型链上</p>
<p>实现原理:</p>
<div class="jb51code"><pre class="brush:js;">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)
    }
}
</pre></div>
<p class="maodian"><a name="_label2"></a></p><h2>三、函数与 this</h2>
<p class="maodian"><a name="_lab2_2_13"></a></p><h3>14. 解释 this 的指向?</h3>
<p>答案:</p>
<ol><li><p>普通函数调用:this 指向全局对象(严格模式下为 undefined)</p></li><li><p>方法调用:this 指向调用该方法的对象</p></li><li><p>构造函数调用:this 指向新创建的实例</p></li><li><p>call/apply/bind 调用:this 指向第一个参数</p></li><li><p>箭头函数:this 指向定义时的上下文,不会改变</p></li></ol>
<p class="maodian"><a name="_lab2_2_14"></a></p><h3>15. call、apply、bind 的区别?</h3>
<p>答案:</p>
<div class="jb51code"><pre class="brush:js;">func.call(thisArg, arg1, arg2, ...)    // 参数逐个传递
func.apply(thisArg, )       // 参数作为数组传递
func.bind(thisArg, arg1, arg2, ...)    // 返回新函数,不立即执行
</pre></div>
<p class="maodian"><a name="_lab2_2_15"></a></p><h3>16. 箭头函数与普通函数的区别?</h3>
<p>答案:</p>
<p>箭头函数没有自己的 this,继承外层</p>
<p>箭头函数没有 arguments 对象</p>
<p>箭头函数不能作为构造函数(不能用 new)</p>
<p>箭头函数没有 prototype 属性</p>
<p>箭头函数不能使用 yield,不能用作生成器</p>
<p class="maodian"><a name="_lab2_2_16"></a></p><h3>17. 什么是高阶函数?</h3>
<p>答案:</p>
<p>接受函数作为参数</p>
<p>或返回一个函数</p>
<p>例如:<code>map、filter、reduce、bind</code></p>
<p>异步编程</p>
<p class="maodian"><a name="_lab2_2_17"></a></p><h3>18. 什么是事件循环?</h3>
<p>答案:</p>
<p>JavaScript 是单线程的,通过事件循环处理异步</p>
<p>任务分为宏任务和微任务</p>
<p>执行顺序:<strong>同步代码 &rarr; 微任务 &rarr; 宏任务</strong></p>
<p>宏任务:<code>setTimeout、setInterval、I/O</code></p>
<p>微任务:<code>Promise.then、process.nextTick、MutationObserver</code></p>
<p class="maodian"><a name="_lab2_2_18"></a></p><h3>19. Promise 的状态?</h3>
<p>答案:</p>
<p><code>pending</code>:初始状态</p>
<p><code>fulfilled</code>:操作成功完成</p>
<p><code>rejected</code>:操作失败</p>
<p>状态一旦改变就不会再变</p>
<p class="maodian"><a name="_lab2_2_19"></a></p><h3>20. Promise 的常用方法?</h3>
<p>答案:</p>
<div class="jb51code"><pre class="brush:js;">Promise.resolve(value)   // 返回 resolved 状态的 Promise
Promise.reject(reason)   // 返回 rejected 状态的 Promise
Promise.all(iterable)      // 所有成功才成功,一个失败就失败
Promise.race(iterable)   // 第一个改变状态的 Promise 决定结果
Promise.allSettled(iterable) // 所有 Promise 都完成后返回结果数组
</pre></div>
<p class="maodian"><a name="_lab2_2_20"></a></p><h3>21. async/await 的优点?</h3>
<p>答案:</p>
<p>代码更简洁,类似同步写法</p>
<p>更好的错误处理(可以使用 <code>try-catch</code>)</p>
<p>更容易调试</p>
<p>避免回调地狱</p>
<p class="maodian"><a name="_lab2_2_21"></a></p><h3>22. 实现一个 Promise?</h3>
<p>答案:</p>
<div class="jb51code"><pre class="brush:js;">class MyPromise {
    constructor(executor) {
      this.state = 'pending'
      this.value = undefined
      this.reason = undefined
      
      const resolve = (value) =&gt; {
            if (this.state === 'pending') {
                this.state = 'fulfilled'
                this.value = value
            }
      }
      
      const reject = (reason) =&gt; {
            if (this.state === 'pending') {
                this.state = 'rejected'
                this.reason = reason
            }
      }
      
      try {
            executor(resolve, reject)
      } catch (err) {
            reject(err)
      }
    }
   
    then(onFulfilled, onRejected) {
      // 简化实现,实际更复杂
      if (this.state === 'fulfilled') {
            onFulfilled(this.value)
      }
      if (this.state === 'rejected') {
            onRejected(this.reason)
      }
    }
}
</pre></div>
<p class="maodian"><a name="_label3"></a></p><h2>四、ES6+ 新特性</h2>
<p class="maodian"><a name="_lab2_3_22"></a></p><h3>23. 解构赋值的用途?</h3>
<p>答案:</p>
<div class="jb51code"><pre class="brush:js;">// 数组解构
const =

// 对象解构
const { name, age } = { name: 'John', age: 30 }

// 函数参数解构
function foo({ x, y }) { return x + y }

// 交换变量
=
</pre></div>
<p class="maodian"><a name="_lab2_3_23"></a></p><h3>24. 扩展运算符的用途?</h3>
<p>答案:</p>
<div class="jb51code"><pre class="brush:js;">// 复制数组
const arr2 = [...arr1]

// 合并数组
const arr3 = [...arr1, ...arr2]

// 函数参数
Math.max(...numbers)

// 对象浅拷贝
const obj2 = { ...obj1 }
</pre></div>
<p class="maodian"><a name="_lab2_3_24"></a></p><h3>25. 模板字符串的特性?</h3>
<p>答案:</p>
<div class="jb51code"><pre class="brush:js;">// 支持换行
const str = `第一行
第二行`

// 支持表达式
const name = 'John'
const greeting = `Hello, ${name}!`

// 标签模板
function tag(strings, ...values) {
    // strings: 模板字符串的静态部分
    // values: 表达式的值
}
</pre></div>
<p class="maodian"><a name="_lab2_3_25"></a></p><h3>26. Symbol 的作用?</h3>
<p>答案:</p>
<p>创建唯一的值,避免属性名冲突</p>
<p>可用作对象的私有属性</p>
<p>内置 <code>Symbol</code> 值如 <code>Symbol.iterator、Symbol.toStringTag</code></p>
<p class="maodian"><a name="_lab2_3_26"></a></p><h3>27. Set 和 Map 的区别?</h3>
<p>答案:</p>
<p><code>Set</code>:值的集合,值唯一</p>
<p><code>Map</code>:键值对的集合,键可以是任意类型</p>
<p><code>WeakSet</code>:弱引用集合,只能存对象</p>
<p><code>WeakMap</code>:弱引用键值对,键只能是对象</p>
<p class="maodian"><a name="_label4"></a></p><h2>五、DOM 与 BOM</h2>
<p class="maodian"><a name="_lab2_4_27"></a></p><h3>28. 事件委托是什么?</h3>
<p>答案:</p>
<p>将事件监听器绑定到父元素</p>
<p>利用事件冒泡机制处理子元素事件</p>
<p>优点:减少内存消耗,动态元素也能处理</p>
<p class="maodian"><a name="_lab2_4_28"></a></p><h3>29. 事件冒泡和事件捕获?</h3>
<p>答案:</p>
<p><strong>事件冒泡</strong>:从目标元素向上传播到根元素</p>
<p><strong>事件捕获</strong>:从根元素向下传播到目标元素</p>
<p><strong>DOM 事件流</strong>:捕获 &rarr; 目标 &rarr; 冒泡</p>
<p><code>addEventListener</code> 第三个参数控制阶段</p>
<p class="maodian"><a name="_lab2_4_29"></a></p><h3>30. 阻止事件默认行为和冒泡?</h3>
<p>答案:</p>
<div class="jb51code"><pre class="brush:js;">event.preventDefault()    // 阻止默认行为
event.stopPropagation()   // 阻止冒泡
event.stopImmediatePropagation() // 阻止同一事件的其他监听器
</pre></div>
<p class="maodian"><a name="_label5"></a></p><h2>六、性能与安全</h2>
<p class="maodian"><a name="_lab2_5_30"></a></p><h3>31. 什么是防抖和节流?</h3>
<p>答案:</p>
<p><strong>防抖</strong>:事件触发后延迟执行,如果期间再次触发则重新计时</p>
<p><strong>节流</strong>:在一定时间内只执行一次</p>
<div class="jb51code"><pre class="brush:js;">// 防抖
function debounce(fn, delay) {
    let timer
    return function(...args) {
      clearTimeout(timer)
      timer = setTimeout(() =&gt; fn.apply(this, args), delay)
    }
}

// 节流
function throttle(fn, delay) {
    let lastTime = 0
    return function(...args) {
      const now = Date.now()
      if (now - lastTime &gt;= delay) {
            fn.apply(this, args)
            lastTime = now
      }
    }
}
</pre></div>
<p class="maodian"><a name="_lab2_5_31"></a></p><h3>32. 什么是跨域?如何解决?</h3>
<p>答案:</p>
<p>浏览器同源策略限制</p>
<p>解决方案:</p>
<div class="jb51code"><pre class="brush:js;">JSONP(仅 GET 请求)

CORS(服务器设置响应头)

代理服务器

postMessage

WebSocket
</pre></div>
<p class="maodian"><a name="_lab2_5_32"></a></p><h3>33. 什么是 XSS 攻击?如何防范?</h3>
<p>答案:</p>
<p>跨站脚本攻击,注入恶意脚本</p>
<p>防范措施:</p>
<p>输入过滤和转义</p>
<p>设置 HttpOnly Cookie</p>
<p>使用 CSP(内容安全策略)</p>
<p>避免内联事件处理</p>
<p class="maodian"><a name="_lab2_5_33"></a></p><h3>34. 什么是 CSRF 攻击?如何防范?</h3>
<p>答案:</p>
<p>跨站请求伪造,诱导用户发送恶意请求</p>
<p>防范措施:</p>
<p>使用 CSRF Token</p>
<p>验证 Referer 头</p>
<p>设置 SameSite Cookie</p>
<p>验证码</p>
<p class="maodian"><a name="_label6"></a></p><h2>七、算法与数据结构</h2>
<p class="maodian"><a name="_lab2_6_34"></a></p><h3>35. 数组去重的方法?</h3>
<p>答案:</p>
<div class="jb51code"><pre class="brush:js;">// 1. Set
[...new Set(array)]

// 2. filter + indexOf
array.filter((item, index) =&gt; array.indexOf(item) === index)

// 3. reduce
array.reduce((acc, cur) =&gt; acc.includes(cur) ? acc : [...acc, cur], [])
</pre></div>
<p class="maodian"><a name="_lab2_6_35"></a></p><h3>36. 数组扁平化的方法?</h3>
<p>答案:</p>
<div class="jb51code"><pre class="brush:js;">// 1. flat
arr.flat(Infinity)

// 2. reduce + 递归
function flatten(arr) {
    return arr.reduce((acc, cur) =&gt;
      Array.isArray(cur)
            ? acc.concat(flatten(cur))
            : acc.concat(cur),
    [])
}

// 3. toString(仅限数字数组)
arr.toString().split(',').map(Number)
</pre></div>
<p class="maodian"><a name="_lab2_6_36"></a></p><h3>37. 深拷贝的实现?</h3>
<p>答案:</p>
<div class="jb51code"><pre class="brush:js;">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 = deepClone(obj, map)
      }
    }
    return clone
}
</pre></div>
<p class="maodian"><a name="_label7"></a></p><h2>八、 浏览器相关</h2>
<p class="maodian"><a name="_lab2_7_37"></a></p><h3>38. 从输入 URL 到页面显示的过程?</h3>
<p>答案:</p>
<p>DNS 解析</p>
<p>TCP 连接</p>
<p>发送 HTTP 请求</p>
<p>服务器处理请求并返回响应</p>
<p>浏览器解析渲染</p>
<p>连接结束</p>
<p class="maodian"><a name="_lab2_7_38"></a></p><h3>39. 重排和重绘?</h3>
<p>答案:</p>
<p>重排:布局改变,需要重新计算</p>
<p>重绘:外观改变,不需要重新布局</p>
<p>优化:<code>避免频繁操作 DOM,使用 transform 和 opacity</code></p>
<p class="maodian"><a name="_lab2_7_39"></a></p><h3>40. 内存泄漏的原因?</h3>
<p>答案:</p>
<p>意外的全局变量</p>
<p>未清理的定时器</p>
<p>闭包滥用</p>
<p>未解绑的事件监听</p>
<p>DOM 引用未清除</p>
<p class="maodian"><a name="_label8"></a></p><h2>九、模块化</h2>
<p class="maodian"><a name="_lab2_8_40"></a></p><h3>41. CommonJS 和 ES6 Module 的区别?</h3>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026011110263378.png" /></p>
<p class="maodian"><a name="_lab2_8_41"></a></p><h3>42. AMD 和 CMD 的区别?</h3>
<p>答案:</p>
<p><code>AMD</code>:异步加载,提前执行(RequireJS)</p>
<p><code>CMD</code>:异步加载,延迟执行(SeaJS)</p>
<p>现在多用 <code>ES6 Module</code></p>
<p>其他重要概念</p>
<p class="maodian"><a name="_lab2_8_42"></a></p><h3>43. 什么是柯里化?</h3>
<p>答案:</p>
<p>将多参数函数转化为单参数函数序列</p>
<div class="jb51code"><pre class="brush:js;">function curry(fn) {
    return function curried(...args) {
      if (args.length &gt;= fn.length) {
            return fn.apply(this, args)
      } else {
            return function(...args2) {
                return curried.apply(this, args.concat(args2))
            }
      }
    }
}
</pre></div>
<p class="maodian"><a name="_lab2_8_43"></a></p><h3>44. 什么是函数组合?</h3>
<p>答案:</p>
<p>将多个函数组合成一个新函数</p>
<div class="jb51code"><pre class="brush:js;">function compose(...fns) {
    return function(x) {
      return fns.reduceRight((acc, fn) =&gt; fn(acc), x)
    }
}
</pre></div>
<p class="maodian"><a name="_lab2_8_44"></a></p><h3>45. 什么是尾调用优化?</h3>
<p>答案:</p>
<p>函数最后一步调用另一个函数</p>
<p><strong>ES6 严格模式下支持</strong></p>
<p>可以优化递归性能</p>
<p class="maodian"><a name="_lab2_8_45"></a></p><h3>46. Generator 函数的作用?</h3>
<p>答案:</p>
<p>可以暂停执行和恢复执行</p>
<p>配合 <code>yield</code> 使用</p>
<p>常用于异步编程(<code>async/await</code> 的基础)</p>
<div class="jb51code"><pre class="brush:js;">function* gen() {
    yield 1
    yield 2
    return 3
}
</pre></div>
<p class="maodian"><a name="_lab2_8_46"></a></p><h3>47. Proxy 和 Reflect?</h3>
<p>答案:</p>
<p><code>Proxy</code>:代理对象,拦截操作</p>
<p><code>Reflect</code>:操作对象的 API,与 <code>Proxy</code> 对应</p>
<div class="jb51code"><pre class="brush:js;">const proxy = new Proxy(target, {
    get(target, prop) {
      return Reflect.get(target, prop)
    }
})
</pre></div>
<p class="maodian"><a name="_lab2_8_47"></a></p><h3>48. WeakMap 和 WeakSet 的特点?</h3>
<p>答案:</p>
<p>弱引用,不影响垃圾回收</p>
<p>键/值必须是对象</p>
<p>不可遍历</p>
<p>没有 size 属性</p>
<p class="maodian"><a name="_lab2_8_48"></a></p><h3>49. 什么是 Optional Chaining?</h3>
<p>答案:</p>
<p>ES2020 新增,可选链操作符 <code>?.</code></p>
<p>避免访问嵌套对象时的空值错误</p>
<div class="jb51code"><pre class="brush:js;">const name = obj?.user?.name
</pre></div>
<p class="maodian"><a name="_lab2_8_49"></a></p><h3>50. 什么是 Nullish Coalescing?</h3>
<p>答案:</p>
<p>ES2020 新增,空值合并操作符 <code>??</code></p>
<p>仅在左侧为 null 或 undefined 时返回右侧</p>
<div class="jb51code"><pre class="brush:js;">const value = a ?? 'default'
</pre></div>
<p class="maodian"><a name="_label9"></a></p><h2>总结&nbsp;</h2>
頁: [1]
查看完整版本: 50道JavaScript高频面试题及答案总结大全