剩余参数的理解扩展运算符用在函数参数上时,也可以将一系列分离的参数整合成一个数组:functionmultiple(...args){让结果=1;for(varvalofargs){结果*=val;}returnresult;}mutiple(1,2,3,4)//24这里给mutiple传入了四个独立的参数,但是如果你尝试在multiple函数中输出args的值,你会发现它是一个array:functionmultiple(...args){console.log(args)}mutiple(1,2,3,4)//[1,2,3,4]这是rest运算符的另一个级别,它可以将函数的多个输入参数收敛到一个数组中。这一点常用于获取函数的冗余参数,或者像上面这样处理函数参数个数不确定的情况。你用过PWA吗?serviceWorker的使用原理是什么?Progressivewebapplication(PWA)是Google在2015年底提出的一个概念。基本上是一个web应用程序,但外观和感觉类似于原生应用程序。支持PWA的网站可以提供离线工作、推送通知和设备硬件访问等功能。ServiceWorkers是浏览器独立于网页在后台运行的脚本,为不需要网页或用户交互的功能打开了大门。它们现在包括推送通知和后台同步等功能。将来,ServiceWorkers将支持其他功能,例如定期同步或地理围栏。本教程中讨论的核心功能是拦截和处理网络请求,包括以编程方式管理缓存中的响应。ES6使用prototype实现继承Object.create()会创建一个“新”对象,然后将这个对象内部的[[Prototype]]与你指定的对象(Foo.prototype)相关联。Object.create(null)创建一个带有空[[Prototype]]链接的对象,该链接不能被委托。functionFoo(name){this.name=name;}Foo.prototype.myName=function(){returnthis.name;}//继承属性,借用构造函数调用functionBar(name,label){Foo.call(这个,名字);this.label=label;}//继承方法,创建备份Bar.prototype=Object.create(Foo.prototype);//必须设置回正确的构造函数,否则判断会报错Bar.prototype.constructor=酒吧;//必须在上一步之后Bar.prototype.myLabel=function(){returnthis.label;}vara=newBar("a","obja");a.我的名字();//"a"a.myLabel();//"obja"代码输出asyncfunctionasync1(){console.log("async1start");等待async2();console.log("async1end");}asyncfunctionasync2(){console.log("async2");}console.log("scriptstart");setTimeout(function(){console.log("setTimeout");},0);async1();newPromise(resolve=>{console.log("promise1");resolve();}).then(function(){console.log("promise2");});console.log('scriptend')输出如下:scriptstartasync1startasync2promise1scriptendasync1endpromise2setTimeout代码执行过程如下:一开始定义了async1和async2两个函数,但是没有执行,而是执行了脚本中的代码,所以打印了scriptstart;当遇到定时器Settimeout时,为宏任务,设置为加入宏任务队列;然后执行函数async1,先打印出async1start;遇到await,执行async2,打印出async2,并阻塞下面代码的执行,将下面代码添加到微任务队列;然后跳出async1和async2,遇到Promise时,打印出promise1;遇到resolve,加入microtask队列,然后执行下面的脚本代码,打印出scriptend;之后就是执行微任务队列的时候了,先打印出async1end,再打印出promise2;执行完microtask队列后,开始执行macrotask队列中的定时器,并打印出setTimeoutJS数据类型基本类型:Number、Boolean、String、null、undefined、symbol(ES6新加入)、BigInt(ES2020)引用类型:Object、对象子类型(Array、Function)说说HTTP和HTTPS的区别协议?1、HTTPS协议需要CA证书,价格昂贵;而HTTP协议不需要它。2、HTTP协议是一种超文本传输??协议,信息以明文形式传输。HTTPS是一种安全的SSL加密传输协议;3.使用不同连接方式和端口也不同,HTTP协议端口为80,HTTPS协议端口为443;4、HTTP协议连接非常简单,无状态;HTTPS协议由SSL和HTTP协议构建而成,可以进行加密传输和身份认证,网络协议比HTTP更安全。详细答案参考前端进阶面试题。JSONPJSONP核心原则:脚本标签不受同源策略约束,因此可以用于跨域请求。优点是兼容性好,但只能用于GET请求。;constjsonp=({url,params,callbackName})=>{constgenerateUrl=()=>{letdataSrc=''for(letkeyinparams){if(params.hasOwnProperty(key)){dataSrc+=`${key}=${params[key]}&`}}dataSrc+=`callback=${callbackName}`return`${url}?${dataSrc}`}returnnewPromise((resolve,reject)=>{constscriptEle=document.createElement('script')scriptEle.src=generateUrl()document.body.appendChild(scriptEle)窗口[callbackName]=data=>{resolve(data)document.removeChild(scriptEle)}})}事件总线(发布-订阅模式)classEventEmitter{constructor(){this.cache={}}on(name,fn){if(this.cache[name]){this.cache[name].push(fn)}else{this.cache[name]=[fn]}}off(name,fn){lettasks=this.cache[name]if(tasks){constindex=tasks.findIndex(f=>f===fn||f.callback===fn)if(index>=0){任务。splice(index,1)}}}emit(name,once=false,...args){if(this.cache[name]){//创建一个副本,如果回调函数继续注册相同的事件,它会导致无限循环}//测试leteventBus=newEventEmitter()letfn1=function(name,age){console.log(`${name}${age}`)}letfn2=function(name,age){console.log(`hello,${name}${age}`)}eventBus.on('aaa',fn1)eventBus.on('aaa',fn2)eventBus.emit('aaa',false,'Bran',12)//'Bran12'//'你好,布兰12'如何优化动画?至于如何优化动画,我们知道在一般情况下,动画需要频繁操作DOM,这会导致页面出现性能问题。我们可以将动画的position属性设置为absolute或者fixed来将动画和文档流分开,这样他的reflow就不会影响到页面了。同时发起10个Ajax请求,全部返回显示结果,最多允许失败3次。说起设计思路,相信很多人第一时间会想到Promise.all,但是这个功能有一个局限性,原因就是失败一次就会返回。直接实现会有点问题,需要变通。下面是两个实现思路//下面是一段不完整的代码,重点说一下非Promise写法的思路letsuccessCount=0leterrorCount=0letdatas=[]ajax(url,(res)=>{if(success){success++if(success+errorCount===10){console.log(datas)}else{datas.push(res.data)}}else{errorCount++if(errorCount>3){//如果失败的次数大于3,应该报错throwError('失败三次')}}})//Promise写法leterrorCount=0letp=newPromise((resolve,reject)=>{if(success){resolve(res.data)}else{errorCount++if(errorCount>3){//如果失败次数大于3,应该报错reject(error)}else{resolve(error)}}})Promise.all([p]).then(v=>{console.log(v);});代码输出functionPerson(name){this.name=name}varp2=newPerson('king');console.log(p2.__proto__)//Person.prototypeconsole.log(p2.__proto__.__proto__)//Object。原型econsole.log(p2.__proto__.__proto__.__proto__)//nullconsole.log(p2.__proto__.__proto__.__proto__.__proto__)//null后面什么都没有,报错console.log(p2.__proto__.__proto__.__proto__.__proto__.__proto__)//null没有了,报错console.log(p2.constructor)//Personconsole.log(p2.prototype)//undefinedp2是一个实例,没有原型属性console.log(Person.constructor)//FunctionEmptyfunctionconsole.log(Person.prototype)//打印出Person.prototype对象中的所有方法和属性console.log(Person.prototype.constructor)//Personconsole.log(Person.prototype.__proto__)//对象.prototypeconsole.log(Person.__proto__)//Function.prototypeconsole.log(Function.prototype.__proto__)//Object.prototypeconsole.log(Function.__proto__)//Function.prototypeconsole.log(Object.__proto__))//Function.prototypeconsole.log(Object.prototype.__proto__)//null这个道德题目考察了原型和原型链的基础,记住就行了。数据类型判断typeof可以正确识别:Undefined,Boolean,Number,String,Symbol,Function等数据类型,但是对于其他的,会被认为是object,比如Null,Date等,所以会通过typeof判断数据类型不准确。但是可以使用Object.prototype.toString来实现。functiontypeOf(obj){-letres=Object.prototype.toString.call(obj).split('')[1]-res=res.substring(0,res.length-1).toLowerCase()-返回res//更好的写法+returnObject.prototype.toString.call(obj).slice(8,-1).toLowerCase()}typeOf([])//'array'typeOf({})//'object'typeOf(newDate)//'date'浏览器渲染优化(1)对于JavaScript:JavaScript不仅会阻塞HTML的解析,还会阻塞CSS的解析。因此,我们可以改变JavaScript的加载方式来优化:(1)尽量把JavaScript文件放在body的末尾(2)尽量不要把标签导入资源的方式分为三种,一种是我们经常使用的直接导入,另外两种是使用async属性和defer属性的异步导入,这两种都是用来异步加载外部JS文件的,不会阻塞DOM解析(尽量使用异步加载)。三者的区别在于:脚本立即停止页面渲染加载资源文件,加载资源后立即执行js代码,执行完js代码后继续渲染页面;async下载完成后立即异步加载,加载后立即执行,多个带有async属性的标签,不能保证加载顺序;defer在下载完成后立即异步加载。加载后,如果还没有构建DOM树,会在解析完DOM树后执行;如果DOM树准备就绪,它将立即执行。多个具有defer属性的标签按顺序执行。(2)对于CSS:CSS的使用方式有3种:使用link、@import和内联样式,其中link和@import都导入外部样式。它们的区别:link:浏览器会发送一个新的等待线程(HTTP线程)去加载资源文件,而GUI渲染线程会继续向下渲染代码@import:GUI渲染线程会暂时停止渲染去向服务器加载资源文件,直到资源文件返回(阻塞浏览器渲染)才会继续渲染。style:GUI直接渲染外部风格。如果长时间没有加载,浏览器会使用浏览器默认的样式来进行用户体验,保证首次渲染速度。所以CSS一般写在headr中,以便浏览器尽快发出获取CSS样式的请求。因此,在开发过程中,使用链接而不是@import导入外部样式。如果css少,尽量使用内联样式,直接写在style标签中。(3)对于DOM树和CSSOM树:可以通过以下方式减少渲染时间:HTML文件的代码层次不要太深,使用语义标签,避免非标准的语义特殊处理,减少CSSD代码层次结构,因为选择器是从左到右解析的(4)减少回流和重绘:在操作DOM时,尽量在低级DOM节点上操作,不要使用表格布局,一个小的改动可能会导致整个表格被改变重新绘制-layout表达式使用CSS不要频繁操作元素的样式。对于静态页面,可以修改类名而不是样式。使用absolute或fixed将元素保持在文档流之外,使它们的更改不会影响其他元素,避免频繁操作DOM。您可以创建文档片段documentFragment,在其上应用所有DOM操作,最后将其添加到文档中。元素先设置display:none,运行完成后再显示。因为对display属性为none的元素进行DOM操作,不会造成回流和重绘。将DOM的多个读取操作(或写入操作)放在一起,而不是穿插写入操作。这是由于浏览器的渲染队列机制。浏览器针对页面的回流和重绘进行了自我优化——渲染队列浏览器会将所有的回流和重绘操作放在一个队列中。当队列中的操作达到一定数量或达到一定时间间隔时,浏览器就会对队列进行批处理。这会将多次回流和重绘变成一次回流重绘。当多个读操作(或写操作)放在一起时,读操作全部进入队列后执行。这样就不会触发多次回流,而是只触发一次回流。如何解决白屏问题1、添加loading2。骨架屏代码输出结果asyncfunctionasync1(){console.log('async1start');awaitnewPromise(resolve=>{console.log('promise1')resolve('promise1resolve')}).then(res=>console.log(res))console.log('async1success');return'async1end'}console.log('srciptstart')async1().then(res=>console.log(res))console.log('srciptend')这里对上面的问题进行修改,加入解决。输出如下:scriptstartasync1startpromise1scriptendpromise1resolveasync1successasync1end什么是僵尸进程和孤儿进程?孤儿进程:当父进程退出,而它的一个或多个进程还在运行时,那么这些子进程就会成为孤儿进程。孤儿进程会被init进程(进程号1)收养,init进程会为他们完成状态收集工作。僵尸进程:子进程先于父进程结束,但是父进程并没有释放子进程占用的资源,所以系统中仍然保存着子进程的进程描述符。这种进程称为僵尸进程。如何防御XSS攻击?可见XSS危害如此之大,所以在开发网站的时候做好防御措施是很有必要的。具体措施如下:可以阻止浏览器的执行。一种是使用纯前端的方式,没有服务端的拼接和返回(没有服务端渲染)。另一种是对需要插入到HTML中的代码进行充分的转义。对于DOM类型的攻击,主要是前端脚本不可靠造成的。对于数据获取、渲染和字符串拼接,需要判断可能存在的恶意代码。使用CSP,CSP的本质是建立一个白名单,告诉浏览器哪些外部资源可以被加载和执行,从而防止恶意代码注入攻击。CSP指的是内容安全策略,其实质就是建立一个白名单,告诉浏览器哪些外部资源可以被加载和执行。我们只需要配置规则,如何拦截是浏览器自己实现的。启用CSP通常有两种方式,一种是在HTTP头中设置Content-Security-Policy,另一种是设置meta标签来保护一些敏感信息,比如对cookie使用http-only,这样无法获取脚本。验证码也可以用来避免脚本冒充用户执行某些操作。什么是文件准备?Webkit和Firefox都做了这个优化。当执行JavaScript脚本时,另一个线程解析剩余的文档并加载稍后需要通过网络加载的资源。这样可以并行加载资源,从而使整体速度更快。需要注意的是,预解析并没有改变DOM树,而是把这个工作交给了主解析过程,它只解析对外部资源的引用,比如外部脚本、样式表和图像。代码constpromise=Promise.resolve().then(()=>{returnpromise;})promise.catch(console.err)输出结果如下:Uncaught(inpromise)TypeError:Chainingcycledetectedforpromise#
