问题当时很开心,而我也自信满满的回答了,可是下一秒就笑不出来了,以为面试官问的问题不一样,没想到是根据这个问题来问的,让他措手不及。回答步履蹒跚。其实面试官会在这个问题上不断“不放过你”,这也取决于你对它的理解和掌握有多深。任何人都可以知道一个常见的问题,很难说出它是什么,但是如果你深挖这个问题,这个技术也可以看到十七八十九,所以不是特别棘手。面试官问的越深,你回答的越多。稳点,面试官一定不喜欢你。这种情况不常遇到,但小编还是整理了一些在高频考点深挖的问题。朋友们,看看你的心底,问题都有答案。面试题经常考var、let和const的区别1.作用域不同(是否包含块级元素)块级作用域:声明的变量只在代码块作用域内有效var没有块-level作用域,let和const有块级作用域2.是否存在临时死区?let和const定义的变量有一个临时死区,但var没有。原理是这样的:对于var,当进入var变量的作用域时,会立即为其创建一个存储空间,对其进行初始化,并赋值给undefined。当函数加载到变量声明语句中时,变量将根据该语句赋值。但是let和const是不同的。当进入一个let变量的作用域时,会立即为其创建存储空间,但不会对其进行初始化。3、是否有变量提升变量提升:变量可以使用var声明变量有变量提升,但是let和const没有变量提升。4.可以重复申报吗?var的声明可以重复,但是let和const的声明不能重复。5.变量可以修改吗?var和let声明的变量可以修改,const声明的常量不能修改面试官深挖的问题1.那么var的作用域是什么?面试的时候被问到这个问题,你知道吗?var的作用域在定义的时候就确定了,如下:如果定义在函数内部,那么var就是一个局部变量,它的作用域称为函数作用域/如果局部作用域定义在函数外部,那么var就是一个全局变量,它的作用域称为全局作用域2.变量提升和函数提升的相关问题//1vara=1;functionb(){vara=2;console.log(a)//输出是什么,为什么}b()//2vara=1;functiona(){}console.log(a)//输出是什么以及为什么//3vara=1;functiona(){console.log(a);}a()//输出是什么?为什么第一个输出2,这个涉及作用域问题,因为变量a定义在b()内部,所有访问函数内部的变量a,所有输出都是2,如果变量a没有在函数内部定义function,然后访问global中定义的a,输出机会为1,第二次输出为1,这里隐藏了变量提升和函数提升的优先级,函数声明提升>变量声明提升。js解析器遇到函数声明时,它会先将它提升到定义体的顶部,然后是var声明的变量,这会导致函数a被变量a覆盖,所以最后会打印1。第三个输出是TypeError:aisnotafunction,与第二个类似。函数a被变量a覆盖了,所以调用a()时会报错,因为a只是一个变量。3.const声明的常量不能改变=>const声明的对象属性可以改变吗?constobj={name:"Ocean",age:18}obj.age=20;console.log(`name:${obj.name},age:${obj.age}`);//outputname:haihai,age:20因为对象是引用类型,obj中只保存了对象的指针,也就是说const只保证指针不变,修改对象的属性会不改变对象的指针,所以是允许的。也就是说,只要const定义的引用类型不变,其他的改变无论如何都是允许的。constobj={name:"Ocean",age:18}//obj.age=20;//console.log(`name:${obj.name},age:${obj.age}`);obj={name:"Ocean",age:18}console.log(`name:${obj.name},age:${obj.age}`);即使对象的内容没有改变,指针已经改变。箭头函数和普通函数的区别箭头函数不需要function关键字来创建函数箭头函数可以省略return关键字箭头函数继承当前上下文的this关键字,箭头函数call、apply、bind是确定和当它们被定义时是固定的它不会影响它的this的指向。箭头函数没有原型。箭头函数没有参数。如果绑定三者的第一个参数为null或undefined,则默认指向window(在浏览器中)。参数列表可以多次传入,apply和call一次传入所有参数)bind改变this的指向后不会立即执行,而是返回一个永久改变this的指向的函数供我们手动调用;apply,call立即调用2.箭头函数的this是怎么确定的varname='Xiaodu'functionb(){console.log(this);//窗口varname='小白'c=()=>{console.log(this.name);}c()}b()这里箭头函数c定义在普通函数b中,所以箭头函数c的this指向普通函数b的this,这里普通函数的this是Global(window),这个需要在浏览器环境下执行,在node环境下执行的是undefinedPromise的静态方法和实例方法注:这里有些公司会涉及到手写Promise,可以研究下源码实现自己写用手。这个知识点很重要。一定要注意高频测试点和高频测试点!1.首先理解Promisependingpendingfulfilled/resolvedcashing/resolution/successrejectedrejection/failure这三种状态2.Promise对象的状态变化只有两种可能:pending到fulfilled和pending到rejected注意:这两种情况只要一出现,状态就确定了,不会再改变。【静态方法】1.Promise.resolveresolve:将Promise对象的状态从Pending(待定)变为Fulfilled(成功)newPromise(resolve=>{resolve('hellosea')}).then(res=>{console.log(res)})2.Promise.rejectreject:将Promise对象的状态从Pending(待定)更改为Rejected(失败)newPromise(reject=>{reject('hellosea')})。then(res=>{console.log(res)})3.Promise.all比如数组中的p1、p2、p3、p4都执行完了,显示页面。值得注意的是,返回数组结果的顺序不会改变。即使P2返回速度比P1快,顺序仍然是p1、p2、p3、p4Promise。不会继续往下letp1=Promise.resolve('p1')letp2=Promise.resolve('p2')letp3=Promise.resolve('p3')letp4=Promise.resolve('p4')Promise。all([p1,p2,p3,p4]).then(res=>{console.log('success',res);//返回数组}).catch(err=>{console.log('failure',err);})4.Promise.racePromise.race的意思是race,也就是说Promise.race([p1,p2,p3,p4])中的结果快到哪一个就返回结果,不管是否是结果本身就是成功或失败letp1=Promise.resolve('p1')letp2=Promise.resolve('p2')letp3=Promise.reject('p3')letp4=Promise.resolve('p4')Promise.race([p1,p2,p3,p4]).then(res=>{console.log('success',res);//返回数组}).catch(err=>{console.log('Failed',err);})5.Promise.allSettled//ES11的新特性该方法在所有给定的promise被履行或拒绝后返回一个promise,带有一个对象数组,每个对象表示对应的promise结果。当您有多个不依赖于彼此成功完成的异步任务时,或者当您总是想知道每个承诺的结果时,通常会使用它。constpromise1=承诺。解决(3);constpromise2=newPromise((resolve,reject)=>setTimeout(reject,100,'foo'));constpromises=[promise1,promise2];承诺。allSettled(promises).then((results)=>results.forEach((result)=>console.log(result.status)));【实例方法(原型方法)】1.Promise.prototype.then这个方法可以接收两个回调函数作为参数,其中第二个回调函数是可选的。当Promise对象的状态变为Resolved时调用第一个回调函数,当Promise对象的状态变为Rejected时调用第二个回调函数。varp1=newPromise((resolve,reject)=>{resolve('Success!');//or//reject(newError("Anerroroccurred!"));});p1.then(value=>{console.log(value);//成功!},reason=>{console.error(reason);//出了点问题!});2.Promise.prototype.catch这个方法返回一个Promise,只处理拒绝(rejected)的情况。constp=newPromise((resolve,reject)=>{reject('failed')}).catch(err=>{console.log(err);})3.Promise.prototype.finally这个方法,不管上一个promise的成功或失败都会被执行,默认情况下,上一个promise的resolution会原样通过,但finally对自己返回的promise的resolution影响有限。它可以将上次的resolve更改为reject,或者将lastreject更改为Anotherreject,但不能将之前的reject更改为resolve。【默认】varp=Promise.resolve('ok').finally((res)=>{returnres}).then(value=>{console.log('success',value)},(err)=>{console.log('失败',err)});[将之前的resolve改为reject]varp=Promise.resolve('ok').finally(()=>{returnPromise.reject('err')}).then(value=>{console.log('成功',值)},(err)=>{console.log('失败',err)});面试官深挖then的问题有几个参数,then的第二个参数和catch有什么区别?then方法可以接受两个回调函数作为参数。其中,第二个功能是可选的,不是必须提供的。这两个函数都接受从Promise对象传递的值作为参数。then方法返回一个实例(不是原来的Promise实例)【区别】区别1:主要区别是then中第一个函数抛出的异常,其第二个函数无法捕获异常。catch可以被捕获(或者secondthen的第二个函数也可以被捕获);区别2:而then和catch的第二个参数在捕获异常时会采用就近原则。当两者都存在时,then只能捕获then的第二个参数。如果then的第二个参数不存在,catch方法会捕获;【用代码展示then和catch的第二个参数的区别】constp=newPromise((resolve,reject)=>{resolve('Yes')})p.then((res)=>{thrownewError('hello');},(err)=>{console.log(err,'第一个然后捕获错误');}).catch((err1)=>{console.log(err1,'catchcatchestheerror');})我们可以发现then中的第二个函数不能catch自己一个函数抛出的异常可以被catch捕获。如果删除catch,会报错constp=newPromise((resolve,reject)=>{resolve('successful')})p.then((res)=>{thrownewError('hello');},(err)=>{console.log(err,'第一个然后捕获错误');})也可以继续使用then来捕获前面then抛出的错误constp=newPromise((resolve,reject)=>{resolve('successful')})p.then((res)=>{thrownewError('hello');},(err)=>{console.log(err,'第一个然后捕获错误');}).then((res)=>{},(err1)=>{console.log(err1,'第二个n捕获错误');})就近捕获异常的原理就是区别2constp=newPromise((resolve,reject)=>{resolve('successful')})p.then((res)=>{thrownewError('你好');},(err)=>{console.log(err,'先抓到错误');}).then((res)=>{},(err1)=>{console.log(err1,'第二次然后捕获错误');}).catch((err2)=>{console.log(err2,'catchcatcherror');})Promise.all和Promise.race区别[区别]Promise。all成功返回一个成功的数组,失败则返回失败的数据。一旦失败,就不会继续下去了。Promise.race的意思是race,也就是说Promise.race([p1,p2,p3,p4])哪个结果快就返回哪个结果,不管结果本身是成功还是失败[Promise.all]让p1=Promise.resolve('p1')让p2=Promise.resolve('p2')让p3=Promise.reject('p3')让p4=Promise.resolve('p4')Promise.all([p1,p2,p3,p4]).then(res=>{console.log('success',res);//返回数组}).catch(err=>{console.log('Failed',err);})【Promise.race】letp1=Promise.reject('p1')letp2=Promise.resolve('p2')让p3=Promise。拒绝('p3')让p4=Promise.resolve('p4')Promise.race([p1,p2,p3,p4]).then(res=>{console.log('success',res);//返回数组}).catch(err=>{console.log('failed',err);})Promise结合setTimeout猜测输出console.log('start')setTimeout(()=>{console.log('time')})Promise.resolve().then(()=>{console.log('resolve')})console.log('end')【分析】一开始整个脚本作为宏任务执行,同步代码为直接压入执行栈执行,所以先打印出start和endsetTimout作为宏任务放入宏任务队列(next)Promise.then作为微任务放入微任务队列。宏任务执行完毕,查看微任务,找到Promise.then,执行后进入下一个宏任务,找到setTimeout,执行。篇幅有限,前端面试题就不多说了。小编分享了大厂整理的前端面试题PDF。共269页。您只需点击即可免费获取。以下是部分面试题目文档展示。为什么要深入挖掘问题?其实上面的问题说起来不难,但是说简单就不容易了。面试官总是需要比你更进一步的答案。不太多,一步到位。只知道“旧页面传值给新页面”是不够的!需知:如何处理“新页面传回旧页面,考虑新页面crash”?仅仅知道“Object.defineproperty()”是不够的!需要了解:如何监控向DOM添加新属性?只知道“懒加载滚动监控”是不够的!需要了解:延迟加载的其他实现方式如何?知道“PerformanceTimingAPI”还不够!需要了解:具体怎么做,监控指标有什么区别,图片资源的加载如何定时?唉!这是“造火箭的采访,拧螺丝的工作”吗?不必要!这些问题在实际工作中很可能会遇到,之前我也用过它来监控本地缓存。PerformanceTiming是性能监控的良方,都是为了做出更好的web服务,为什么要拒??绝呢?
