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">总结 </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 返回 “object”,这是历史遗留 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>同步代码 → 微任务 → 宏任务</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) => {
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) {
// 简化实现,实际更复杂
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>:捕获 → 目标 → 冒泡</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(() => fn.apply(this, args), delay)
}
}
// 节流
function throttle(fn, delay) {
let lastTime = 0
return function(...args) {
const now = Date.now()
if (now - lastTime >= 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) => array.indexOf(item) === index)
// 3. reduce
array.reduce((acc, cur) => 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) =>
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 >= 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) => 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>总结 </h2>
頁:
[1]