前端面试题-Javascript篇

Javascript

1、解释事件循环(Event Loop)机制

参考链接:JS事件循环(Event Loop)机制-CSDN博客

答:JavaScript 的事件循环(Event Loop)是 JavaScript 运行机制的核心部分,它负责处理代码的执行、事件的处理以及异步操作的调度。

事件循环会不断检查调用栈是否为空:

  • 如果调用栈为空,它会首先检查微任务队列是否有待执行的函数,如果有,就执行这些微任务。

  • 执行完所有微任务后,它会检查宏任务队列,并执行其中的一个任务(通常是时间最接近的任务)。

  • 一旦宏任务执行完毕,再次检查微任务队列,如此循环往复。

2. 什么是闭包?闭包有什么作用和使用场景?

参考链接:Javascript闭包-CSDN博客 

答:闭包是指在JavaScript中,一个内部函数能够访问其外部函数的作用域中的变量,即使外部函数已经执行完毕。闭包由函数及其词法环境组成,内部函数持有外部作用域的变量引用。

闭包的使用场景 :

  1. 防抖和节流‌:在处理高频事件(如窗口缩放、滚动)时,通过闭包保存计时器ID,避免函数被频繁调用‌。

  2. 模块开发‌:使用 IIFE (立即执行函数表达式)返回包含私有方法的对象,实现模块的封装和私有化‌。

  3. 循环陷阱处理‌:在循环中使用闭包绑定正确的循环变量值,防止异步操作中使用错误的循环变量‌。

  4. 高阶函数‌:在柯里化操作中保持参数状态,通过闭包动态生成函数‌。

3. 解释原型链和继承。

参考链接:JS原型链和继承-CSDN博客

答:每个JS对象都有一个隐藏的__proto__属性,指向它的原型对象,当访问对象的属性时,如果对象本身没有该属性,就会沿着原型链向上查找,原型对象也有自己的原型,最终指向null,形成一条链式结构。构造函数通过prototype属性关联原型对象,使用new创建实例时,实例的__proto__会自动指向构造函数的prototype。

4. 如何实现深拷贝?

答:(1)使用JSON.stringify()和JSON.parse(),不能复制函数、Symbol、undefined等特殊类型,会丢失对象的constructor信息.(2)手动遍历对每个对象,递归拷贝。(3)使用第三方库,Lodash的_.cloneDeep(),jQuery的$.extend(true, {}, obj)。(4)MessageChannel API(处理特殊对象),可以复制函数等JSON方法不能处理的对象

5. 解释this关键字的指向。

答:默认指向全局对象(浏览器中为window),在对象中指向调用该方法的对象,使用call/apply/bind函数可强制指定this指向,使用new绑定(构造函数)指向新创建的实例对象,箭头函数继承外层作用域的this(词法作用域)。

6. 解释call、apply、bind的区别。

答:call/apply会立即执行原函数,bind需要返回绑定后的新函数(需手动调用);call的参数逐个传递(逗号分隔),apply的参数通过数组传递,bind支持分步传参(绑定时可预置部分参数);call/apply仅临时修改本次调用的this指向,bind是永久绑定this(除非用new调用)。

方法执行时机参数形式this绑定效果
call立即执行逐个参数临时修改
apply立即执行数组临时修改
bind延迟执行支持分步传参永久绑定(非new)

7. Promise是什么?如何实现一个Promise?

答:Promise 是一种用于处理异步操作的对象,它可以将回调函数变成链式调用,使代码更加清晰和优雅。Promise 有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。状态一旦改变,就不会再变。实现一个基础版的 Promise 类需要包含以下几个部分:

  1. 构造函数:接受一个执行器函数,该函数包含两个参数:resolve 和 reject。

  2. 状态:Promise 有三个状态,初始状态为 pending。

  3. :用于存储成功或失败的值。

  4. 回调队列:用于存储 then 方法传入的回调函数。

8. async/await的工作原理是什么?

:async 和 await 是 JavaScript 中用于处理异步操作的关键字。它们基于 Promise,提供了一种更简洁和直观的方式来编写异步代码,使其看起来像同步代码。

async 关键字用于声明一个异步函数。异步函数会隐式地返回一个 Promise 对象,其结果由函数的返回值决定。

await 关键字用于等待一个 Promise 对象的结果。它只能在 async 函数内部使用。await 会暂停函数的执行,直到 Promise 对象完成,并返回其结果。

9. 解释防抖(debounce)和节流(throttle)以及它们的应用场景。

答: 防抖 (Debounce)和 节流 (Throttle)是两种用于优化高频事件处理的JavaScript技术,主要用于减少函数执行的频率,从而节省资源并提高应用性能。

‌防抖的核心思想是延迟执行,只有在事件触发的频率降低到一定程度后才会执行。‌如果在设定的延迟时间内再次触发事件,则会重新计时,直到用户停止触发事件一段时间后才会执行。比如:

  • 搜索输入框输入停止一段时间后再发送请求,避免因频繁输入而频繁请求
  • 窗口的调整可以在窗口大小稳定后进行触发
  • 表单验证中可以在输入停止一段时间后再进行验证

‌节流的核心思想是保证在特定时间内至少执行一次函数,不论事件触发的频率如何。‌节流适用于那些需要定期执行但不需要过于频繁的场景,例如:

  •  在滚动事件中,如果不加限制地执行函数会导致性能问题。使用节流可以保证在每次滚动时至少执行一次函数,避免过于频繁的执行‌。
  •  在用户快速点击按钮时,防止重复提交表单或执行不必要的操作。使用节流可以确保在特定时间内最多执行一次函数‌。
  •  在用户连续输入时,使用节流可以保证在特定时间内最多执行一次输入处理函数,避免过于频繁的输入处理‌。

10. ES6有哪些新特性?

答:块级作用域变量(let/const)、箭头函数、模板字符串、解构赋值、类和模块系统等

11. 解释箭头函数和普通函数的区别。

答:箭头函数与普通函数的核心区别集中在this绑定规则、构造函数使用限制和语法特性三个方面‌。箭头函数没有独立的this值,继承外层作用域的this;无法作为构造函数使用;语法更简洁但缺少arguments对象和prototype属性。

特征箭头函数普通函数
this绑定静态继承外层作用域动态绑定调用对象
构造函数支持
arguments对象❌(需用剩余参数)
显式绑定this
匿名函数占比可变(具名/匿名)

12. 解释let、const、var的区别。

答:var:仅在声明它的函数内部有效,或在全局作用域中有效,‌声明被提升到作用域顶部,初始化值为 undefined,允许重复声明(可能引发意外覆盖),声明后值可修改,在全局作用域声明时,变量会成为 window 对象的属性。

let:‌‌在块级作用域({} 内有效),在 iffor 等代码块内部声明的变量不会泄漏到外部,存在暂时性死区(TDZ)声明前访问会报错(ReferenceError),但声明本身仍被提升,禁止重复声明,声明后值可修改,不会添加到 window 对象。

const:‌在块级作用域({} 内有效),在 iffor 等代码块内部声明的变量不会泄漏到外部,存在暂时性死区(TDZ)声明前访问会报错(ReferenceError),但声明本身仍被提升,禁止重复声明,声明后值不可修改,不会添加到 window 对象。

特性varletconst
作用域函数作用域块级作用域块级作用域
变量提升✅(值为 undefined✅(TDZ 报错)✅(TDZ 报错)
重复声明允许禁止禁止
重新赋值允许允许禁止
声明时初始化要求可选可选必需
全局作用域绑定到 window

13. 如何判断一个变量的类型?

参考链接:在 JavaScript 中,判断变量类型有多种方法-CSDN博客

答:typeof、instanceof、Object.prototype.toString、Array.isArray()

方法适用场景局限性
typeof基本类型、函数null 返回 "object"
instanceof检测对象实例(如 ArrayDate不适用于基本类型
Object.prototype.toString所有类型(最全面)需手动提取类型字符串
Array.isArray()仅检测数组仅适用于数组

14. 解释跨域问题以及解决方案(如CORS、JSONP等)。

答:浏览器出于安全考虑,对于同源的请求通过,对于不是同源的请求会限制,这就是浏览器的 同源策略,对于不满足浏览器浏览器同源策略出现的开发问题,就是跨域问题。

使用CORS时,浏览器只允许获取默认的响应头,像上文代码中的标头With-Requested-Key,即便我们可以通过浏览器的调试器查看,也无法通过代码去获取,这时候就需要后台通过Access-Control-Expose-Header进行暴露。

使用.JSONP时,通过script标签没有跨域限制的特性,进行资源的请求和获取,需要目标服务器进行配合,且仅支持get请求。

15. 解释前端模块化(CommonJS、AMD、ES6 Module)。

答:CommonJS:

  • 同步加载模块,适用于Node.js服务端环境
  • 通过require()导入、module.exports导出
  • 模块加载后会被缓存,多次require返回相同对象
  • 浏览器端同步加载会阻塞渲

AMD规范:

  • 异步加载,专为浏览器设计(如RequireJS)
  • 使用define()定义模块、require()异步加载
  • 依赖前置声明,提前加载所有依赖

ES6 Module:

  • 原生支持,静态分析依赖关系
  • 通过import/export语法实现
  • 输出的是值的引用(CommonJS是值拷贝)
特性CommonJSAMDES6 Module
加载方式同步异步静态编译
适用环境服务端浏览器全平台
输出形式值拷贝动态绑定实时引用
语法requiredefineimport
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Winter Li

拜托拜托,老板赏赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值