JS面试题大全及详细答案(实战完整版)_第1页
JS面试题大全及详细答案(实战完整版)_第2页
JS面试题大全及详细答案(实战完整版)_第3页
JS面试题大全及详细答案(实战完整版)_第4页
JS面试题大全及详细答案(实战完整版)_第5页
已阅读5页,还剩12页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

JS面试题大全及详细答案(实战完整版)一、JavaScript基础核心面试题1.简述JavaScript的数据类型,以及基本类型和引用类型的区别答案:JS一共有8种数据类型:基本数据类型(7种):String、Number、Boolean、Undefined、Null、Symbol、BigInt引用数据类型(1种):Object(包含普通对象、数组、函数、正则、日期等)核心区别:1.存储位置不同:基本类型值存储在栈内存中,变量直接保存数值本身;引用类型栈内存保存内存地址,真实数据存储在堆内存中。2.赋值机制不同:基本类型赋值是值拷贝,两个变量相互独立,修改一个不会影响另一个;引用类型赋值是地址拷贝,多个变量指向同一个堆内存数据,修改会相互影响。3.比较规则不同:基本类型比较的是数值本身;引用类型比较的是内存地址,内容相同但地址不同,结果也为false。2.null和undefined的区别?答案:1.含义不同:undefined表示变量已声明但未赋值,系统默认初始值;null表示空对象指针,代表人为主动设置的空值。2.类型不同:undefined类型为undefined;null类型为object(历史遗留bug,最初JS底层存储标识错误导致)。3.赋值场景不同:undefined多为系统自动产生;null是开发者手动赋值,用于清空对象、初始化空变量。4.运算区别:null==undefined结果为true(宽松相等,自动类型转换);null===undefined结果为false(严格相等,类型不同)。3.讲讲JS的隐式类型转换规则答案:JS在运算、判断相等、条件语句中会自动触发隐式转换,核心分为三类:1.转换为布尔值(Boolean)假值(转换后为false):0、NaN、null、undefined、''、false其余所有值转换后均为true(空对象、空数组也是真值)2.转换为数字(Number)字符串转数字:纯数字字符串转为对应数字,含非数字字符转为NaN;空字符串转为0布尔值转数字:true=1,false=0null转0,undefined转NaN对象转数字:先调用valueOf(),再调用toString(),最终转为数字或NaN3.转换为字符串(String)数值、布尔值直接转为对应文本;null转为'null',undefined转为'undefined';对象默认转为'[objectObject]'常见坑:[]==0//true,空数组转数字为0[]==''//true,空数组转字符串为空{}=={}//false,引用类型比较地址4.==和===的区别答案:1.==宽松相等:会先进行隐式类型转换,类型不同则转成相同类型后再比较数值,日常开发少用,容易出现诡异问题。2.===严格相等:先比较类型,再比较数值,类型不同直接返回false,不做任何类型转换。是开发首选判断方式。特例:NaN与任何值(包括自身)比较都为false,判断NaN只能用Number.isNaN()。5.解释变量提升、函数提升,以及优先级答案:JS代码执行分为编译阶段和执行阶段,提升发生在编译阶段,会提前扫描声明语句并挂载到对应作用域顶部。1.变量提升:var声明的变量会提升,初始值为undefined;let、const存在暂时性死区,不会提升(无法在声明前访问)。2.函数提升:函数声明(functionfn(){})会整体提升,声明前可直接调用;函数表达式(constfn=function(){})属于变量提升,提升后值为undefined,无法提前调用。提升优先级:函数提升>变量提升同一作用域下,变量和函数同名时,函数声明会覆盖变量声明,变量赋值不会影响已提升的函数。6.什么是暂时性死区(TDZ)?答案:ES6中let、const声明的变量,在代码块开始到变量声明语句之前的区域,称为暂时性死区。核心特点:死区内无法访问、赋值该变量,访问会直接报错UncaughtReferenceError,彻底解决了var变量提升带来的污染问题。只要进入当前块级作用域,变量就已存在,但处于锁定状态,必须等到声明语句执行完毕,才能正常使用。7.var、let、const的区别答案:1.作用域:var是函数作用域;let、const是块级作用域({}、if、for内部独立作用域)。2.提升机制:var存在变量提升;let、const无提升,存在暂时性死区。3.重复声明:var允许重复声明变量;let、const禁止同一作用域重复声明。4.赋值规则:var、let可修改赋值;const声明常量,基本类型不可修改,引用类型可修改内部属性(地址不变即可),且必须初始化赋值。5.全局挂载:var声明的全局变量会挂载到window;let、const不会挂载到window,避免全局变量污染。二、作用域与闭包高频题1.讲讲JS的作用域类型答案:JS作用域用于规范变量的可访问范围,主要分为3种:1.全局作用域:代码最外层,全局变量任何位置都可访问,页面关闭才会销毁。2.函数作用域:函数内部形成的独立作用域,函数执行完毕后,内部变量销毁。3.块级作用域:ES6新增,由{}包裹形成(if、for、while、单独代码块),仅let、const生效,解决了全局变量污染、循环变量泄露问题。2.什么是作用域链?答案:当当前作用域需要访问一个变量时,会先在当前作用域查找,找不到就向上一级父作用域查找,逐级向上,直到全局作用域,这套层级查找机制就是作用域链。查找规则:就近原则,下级作用域变量优先,上级作用域无法访问下级变量。作用域链在函数定义时就已确定,和调用位置无关。3.什么是闭包?闭包的用途、优缺点答案:定义:一个函数可以访问其外部函数作用域变量,即使外部函数已经执行完毕,这种函数+外部作用域变量的组合就是闭包。简单说:内层函数引用外层函数变量,就形成闭包。核心用途:1.保存私有变量,实现模块化封装,避免全局污染;2.缓存数据,保留函数执行后的变量状态;3.实现防抖、节流、柯里化等高阶功能;4.解决for循环定时器变量穿透问题。优点:变量私有化、状态持久化、拓展函数作用域。缺点:外层函数变量无法被垃圾回收,容易造成内存泄漏,滥用会导致页面卡顿。解决办法:使用完毕手动置空闭包引用的变量,解除引用。4.解释内存泄漏,JS常见内存泄漏场景答案:内存泄漏:程序中已不再使用的内存,没有被垃圾回收机制释放,持续占用内存,导致内存占用越来越高。常见场景:1.闭包滥用,持续引用无用变量;2.全局变量过多,未手动销毁;3.定时器、事件监听未清除;4.数组、对象持续添加数据,不做清空;5.DOM节点移除后,JS仍保留节点引用。三、this指向、原型与原型链1.详细说说this的指向规则(必考)答案:this的指向由函数调用方式决定,和定义位置无关,核心5种场景:1.普通函数调用(独立调用):this指向window(浏览器)/global(node),严格模式下指向undefined。2.对象方法调用:谁调用函数,this就指向谁(就近调用对象)。3.构造函数调用(new):this指向new出来的实例对象。4.bind/call/apply绑定:this指向绑定的第一个参数对象。5.箭头函数:箭头函数没有自己的this,继承外层最近一层作用域的this,且this绑定后永久固定,无法被修改。2.call、apply、bind的区别答案:三者作用一致:修改函数this指向,第一个参数均为this绑定对象。区别:1.参数形式:call参数为逐个罗列;apply参数为数组/伪数组;bind参数可逐个罗列,支持预设参数。2.执行时机:call、apply立即执行函数;bind返回新函数,不会立即执行,需手动调用。3.绑定次数:bind绑定的this永久生效,再次绑定无效;call、apply仅单次生效。3.什么是原型、原型链?答案:原型(prototype):每个构造函数都有一个prototype属性,指向一个原型对象,用于存放实例公共方法和属性,实现方法复用,节省内存。原型链(__proto__):每个实例对象都有__proto__属性,指向构造函数的prototype原型对象;原型对象本身也是对象,也有__proto__,逐级向上查找,最终指向Ototype,顶端为null,这条链式结构就是原型链。查找规则:访问对象属性/方法时,先找自身,自身没有则沿原型链向上查找,直到顶端null。4.constructor、prototype、__proto__的关系答案:1.构造函数.prototype:原型对象,存储公共属性方法;2.实例.__proto__:指向所属构造函数的prototype;3.原型对象.constructor:指回对应的构造函数;总结:实例.__proto__===构造函数.prototype,构造函数.prototype.constructor===构造函数。5.new关键字的执行过程答案:1.创建一个空的普通JS对象;2.将空对象的__proto__指向构造函数的prototype原型;3.将构造函数内部的this绑定为这个空对象,执行构造函数代码,给对象添加属性和方法;4.如果构造函数没有返回引用类型值,自动返回创建的实例对象;如果返回对象/数组,则返回该引用值。四、ES6+核心面试题1.箭头函数和普通函数的区别答案:1.this指向:普通函数this由调用方式决定;箭头函数无独立this,继承外层作用域this,且不可修改。2.arguments:箭头函数没有arguments对象,可使用剩余参数...args替代。3.原型:箭头函数没有prototype原型属性,不能作为构造函数,无法new实例。4.generator:箭头函数不能作为生成器函数,不能使用yield关键字。5.适用场景:箭头函数适合回调函数、定时器;不适合对象方法、构造函数、需要this动态指向的场景。2.解构赋值的规则及注意点答案:解构赋值可快速从数组、对象中提取值,简化代码。1.数组解构:按索引顺序匹配,支持默认值、剩余参数。2.对象解构:按属性名匹配,与顺序无关,可重命名、设置默认值。注意点:解构不成功时,变量值为undefined;默认值仅在对应值为undefined时生效,null、0、''不会触发默认值。3.Promise的理解、三种状态、优缺点答案:Promise是ES6异步解决方案,用于解决传统回调地狱问题,封装异步操作。三种状态(不可逆):1.pending等待态:初始状态,异步未完成;2.fulfilled成功态:异步执行成功,状态锁定,触发then回调;3.rejected失败态:异步执行失败,状态锁定,触发catch回调。优点:解决回调地狱、支持链式调用、状态统一管理异步、可并行执行多个异步(Promise.all)。缺点:一旦执行无法取消、错误需要手动捕获、单次异步执行,无法重复使用。4.Promise常用方法(all、race、allSettled、any)答案:1.Promise.all:全部成功才成功,一个失败直接失败,返回所有成功结果数组,适合并行请求、依赖所有结果的场景。2.Promise.race:谁先完成返回谁,无论成功失败,常用于接口超时拦截。3.Promise.allSettled:所有请求执行完毕,不管成功失败,返回每个请求的状态和结果,适合批量请求不报错场景。4.Promise.any:一个成功就成功,全部失败才失败,适合多接口容错、择优请求场景。5.async/await的原理及优缺点答案:async/await是Promise的语法糖,本质基于Promise实现,将异步代码写成同步写法,代码更简洁。1.async:修饰函数,函数返回值自动包装为Promise对象;2.await:只能在async函数内部使用,暂停代码执行,等待Promise状态完成,再继续向下执行。优点:彻底解决回调地狱、代码可读性极高、逻辑清晰、便于调试。缺点:await会阻塞代码执行,多个无依赖的异步不建议单独await,需配合Promise.all并行执行。错误捕获:通过try/catch捕获await异步错误。6.Set和Map的特点及应用场景答案:Set:无序、唯一的集合,元素不可重复,支持任意类型值。特点:自动去重、可遍历、size获取长度。场景:数组去重、存储不重复数据、判断元素是否存在。Map:键值对集合,键可以是任意类型(对象、数组、函数),突破对象key只能是字符串/Symbol的限制。特点:键唯一、有序存储、可遍历、查询效率高。场景:复杂数据键值存储、频繁增删查改数据、缓存数据。五、异步与事件循环(面试重点难点)1.JS为什么是单线程?答案:JS最初设计用于浏览器页面交互、操作DOM、处理用户事件。如果是多线程,多个线程同时操作同一个DOM节点,会出现渲染冲突、覆盖问题,无法统一页面状态。因此JS采用单线程执行机制,保证DOM操作的唯一性和稳定性。为了解决单线程阻塞问题,JS引入异步、事件循环机制,实现非阻塞执行。2.什么是同步、异步?宏任务、微任务区别答案:同步:代码从上到下依次执行,上一行执行完毕才会执行下一行,会阻塞后续代码。异步:代码执行不会阻塞主线程,异步任务放入任务队列,主线程同步代码执行完毕后,再执行异步任务。宏任务&微任务宏任务(耗时较长):script整体代码、setTimeout、setInterval、AJAX、DOM事件、UI渲染。微任务(优先级更高、执行更快):Promise.then/catch/finally、async/await、queueMicrotask、MutationObserver。核心优先级:同步代码>微任务>宏任务3.详细讲解浏览器事件循环机制答案:1.主线程先执行所有同步代码,执行过程中遇到异步任务,分别放入宏任务队列、微任务队列;2.同步代码执行完毕后,清空所有微任务队列(一次性执行完所有微任务);3.微任务清空后,执行一个宏任务;4.再次检查微任务队列,如有新增微任务,继续全部清空;5.循环往复,形成事件循环,保证代码非阻塞执行。高频考点:每执行完一个宏任务,都会重新清空一轮微任务,而非所有宏任务执行完再执行微任务。六、DOM、BOM与浏览器相关1.DOM事件流机制答案:DOM事件触发分为三个阶段,从上到下依次执行:1.捕获阶段:事件从window自上而下逐级传递到目标元素;2.目标阶段:事件到达触发的目标元素,执行绑定事件;3.冒泡阶段:事件从目标元素自下而上逐级冒泡回window。addEventListener第三个参数:true捕获阶段触发,false(默认)冒泡阶段触发。2.事件冒泡、事件委托的原理和优势答案:事件冒泡:子元素触发事件后,会向上传递给所有父元素,父元素同名事件也会触发。事件委托:利用事件冒泡机制,将子元素的事件绑定到父元素,统一处理所有子元素事件。优势:1.减少事件绑定次数,节省内存;2.支持动态新增的DOM元素事件生效,无需重复绑定;3.简化代码逻辑,统一管理事件。3.如何阻止事件冒泡和默认行为答案:1.阻止冒泡:e.stopPropagation(),阻止事件向上冒泡传递;2.阻止默认行为:e.preventDefault(),阻止标签默认行为(a标签跳转、表单提交、右键菜单等);3.兼容写法:returnfalse(仅原生事件有效,可同时阻止冒泡和默认行为,不推荐通用)。4.浏览器缓存机制(强缓存、协商缓存)答案:浏览器缓存用于减少重复请求,提升页面加载速度,分为强缓存和协商缓存。1.强缓存(优先级最高,不发请求)响应头:Cache-Control(max-age)、Expires规则:资源未过期,直接读取本地缓存,状态码200(frommemorycache/diskcache)。2.协商缓存(过期后触发,发请求校验)响应头:Last-Modified/If-Modified-Since、ETag/If-None-Match规则:资源过期后,携带标识请求服务端,服务端对比资源是否更新;未更新返回304,使用本地缓存;更新则返回新资源200。七、高频手写源码题(面试必刷)1.手写数组去重(多种方法)答案:javascript

//方法1:Set去重(最简)

functionunique1(arr){

return[...newSet(arr)]

}

//方法2:filter+indexOf

functionunique2(arr){

returnarr.filter((item,index)=>arr.indexOf(item)===index)

}

//方法3:双重for循环

functionunique3(arr){

letres=[]

for(leti=0;i<arr.length;i++){

letflag=true

for(letj=0;j<res.length;j++){

if(arr[i]===res[j])flag=false

}

if(flag)res.push(arr[i])

}

returnres

}2.手写深拷贝答案:javascript

functiondeepClone(obj){

//基础类型、null、undefined直接返回

if(obj===null||typeofobj!=='object')returnobj

//处理日期、正则

if(objinstanceofDate)returnnewDate(obj)

if(objinstanceofRegExp)returnnewRegExp(obj)

//创建新对象/数组

letnewObj=Array.isArray(obj)?[]:{}

//递归遍历赋值

for(letkeyinobj){

if(obj.hasOwnProperty(key)){

newObj[key]=deepClone(obj[key])

}

}

returnnewObj

}3.手写防抖、节流答案:防抖:触发后延迟执行,期间再次触发重置延迟,只执行最后一次javascript

functiondebounce(fn,delay=300){

lettimer=null

returnfunction(...args){

if(timer)clearTimeout(timer)

timer=setTimeout(()=>{

fn.apply(this,args)

timer=null

},delay)

}

}节流:固定时间内只执行一次,防止高频触发javascript

functionthrottle(fn,interval=300){

letlastTime=0

returnfunction(...args){

letnow=Date.now()

if(now-lastTime>=interval){

fn.apply(this,args)

lastTime=now

}

}

}4.手写call/apply/bind答案:javascript

//手写call

Ftotype.myCall=function(context,...args){

context=context||window

//创建唯一属性,防止覆盖原有属性

constkey=Symbol()

context[key]=this

//执行函数

constres=context[key](...args)

//删除临时属性

deletecontext[key]

returnres

}

//手写apply

Ftotype.myApply=function(context,args=[]){

context=context||window

constkey=Symbol()

context[key]=this

constres=context[key](...args)

deletecontext[key]

returnres

}

//手写bind

Ftotype.myBind=function(context,...args1){

constfn=this

returnfunction(...args2){

returnfn.myCall(context,...args1,...args2)

}

}5.手写Promise答案:javascript

classMyPromise{

constructor(executor){

this.status='pending'

this.value=undefined

this.reason=undefined

this.onFulfilledCallbacks=[]

this.onRejectedCallbacks=[]

constresolve=(value)=>{

if(this.status==='pending'){

this.status='fulfilled'

this.value=value

this.onFulfilledCallbacks.forEach(fn=>fn())

}

}

constreject=(reason)=>{

if(this.status==='pending'){

this.status='rejected'

this.reason=reason

this.onRejectedCallbacks.forEach(fn=>fn())

}

}

try{

executor(resolve,reject)

}catch(err){

reject(err)

}

}

then(onFulfilled,onRejected){

onFulfilled=typeofonFulfilled==='function'?onFulfilled:val=>val

onRejected=typeofonRejected==='function'?onRejected:err=>{throwerr}

constnewPromise=newMyPromise((resolve,reject)=>{

//成功态

if(this.status==='fulfilled'){

setTimeout(()=>{

try{

letres=onFulfilled(this.value)

resolve(res)

}catch(err){

reject(err)

}

})

}

//失败态

if(this.status==='rejected'){

setTimeout(()=>{

try{

letres=onRejected(this.reason)

resolve(res)

}catch(err){

reject(err)

}

})

}

//等待态,存储回调

if(this.status==='pending'){

this.onFulfilledCallbacks.push(()=>{

setTimeout(()=>{

try{

letres=onFulfil

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论