当前位置: 首页 > Web前端 > HTML

高级前端双面面试题

时间:2023-03-29 13:10:41 HTML

如果一个构造函数绑定了一个对象,那么用这个构造函数创建的实例会继承对象的属性吗?为什么?没有继承,因为根据这个绑定的四个规则,new绑定的优先级高于bind显示绑定。当通过new调用构造函数时,会创建一个新对象,这个新对象会代替bind的对象绑定,作为这个函数的this,如果这个函数没有返回对象,就返回这个新创建的对象TCP和UDP使用场景TCP应用场景:效率要求比较低,准确率要求比较高的场景。由于在传输过程中需要进行数据确认、重传、排序等操作,效率没有UDP高。比如:文件传输(精度要求高,但速度可以相对慢一些),接受邮件,远程登录。UDP应用场景:效率要求比较高,精度要求比较低的场景。例如:QQ聊天、在线视频、VoIP(即时通讯,速度要求高,但偶尔中断问题不大,这里不能使用重传机制)、广播通信(广播、组播)。POST和PUT请求的区别PUT请求是向服务器发送数据,修改数据的内容,但是不会增加数据的类型等,也就是说无论多少次PUT执行操作,结果没有什么不同。(可以理解为更新数据的时间)POST请求是向服务器发送数据,请求会改变数据和其他资源的类型,会创建新的内容。(可以理解为创建数据)闭包的应用场景Curriedbind模块Newoperator是做什么的?1.首先新建一个对象2.设置原型,将对象的原型设置为函数的原型对象3.让函数的this指向这个对象,执行构造函数的代码(给这个新对象添加属性)4.判断函数的返回值类型。如果是值类型,则返回创建的对象。如果是引用类型,则返回该引用类型的目标代码输出结果constasync1=async()=>{console.log('async1');setTimeout(()=>{console.log('timer1')},2000)awaitnewPromise(resolve=>{console.log('promise1')})console.log('async1end')return'async1success'}console.log('scriptstart');async1().then(res=>console.log(res));console.log('scriptend');Promise.resolve(1).then(2).then(Promise.resolve(3)).catch(4).then(res=>console.log(res))setTimeout(()=>{console.log('timer2')},1000)输出结果如下:scriptstartasync1promise1scriptend1timer2timer1代码的执行过程如下:首先执行正时皮带,打印Executescriptstart;遇到定时器timer1,加入宏任务队列;然后执行Promise并打印出promise1。由于Promise没有返回值,所以下面的代码不会被执行;然后执行同步代码并打印出脚本结束;continue执行下面的Promise,.then和.catch期望参数是一个函数,这里传入一个数字,所以会发生值穿透,resolve(1)的值会传给最后的then,和1将直接打印;到第二个定时器,加入microtask队列,执行microtask队列,依次执行两个定时器,但是由于定时器时间的关系,两秒后会打印出timer2,四秒后再打印出timer1。WebSocket的理解WebSocket是HTML5提供的一种用于浏览器和服务器之间全双工通信的网络技术,属于应用层协议。它基于TCP传输协议,重用了HTTP握手通道。浏览器和服务器只需要完成一次握手,两者之间就可以直接建立持久连接,进行双向数据传输。WebSocket的出现解决了半双工通信的弊端。它最大的特点是服务端可以主动向客户端推送消息,客户端也可以主动向服务端推送消息。WebSocket原理:客户端通知(notify)一个事件(event),带有所有接收者ID(recipientsID)给WebSocket服务器,服务器收到后立即通知所有活跃(active)的客户端,接收者ID中只有IDsequence中的客户端会处理这个事件。WebSocket的特点如下:支持双向通信,实时性更强,可以发送文本,也可以发送二进制数据''基于TCP协议,服务端实现比较容易,数据格式比较轻,性能开销小,通信效率高。同源限制,客户端可以与任何服务器通信。协议标识为ws(加密后为wss),服务器URL为URL。对HTTP协议有很好的兼容性。默认的端口也是80和443,而且握手阶段使用的是HTTP协议,所以在握手的时候不容易屏蔽,可以通过各种HTTP代理服务器。Websocket的使用方法如下:在客户端://在index.html中直接写WebSocket,设置服务端的端口号为9999letws=newWebSocket('ws://localhost:9999');//在客户端触发ws.onopen=function(){console.log("Connectionopen.");ws.send('hello');};//从服务器向客户端发送消息触发器ws.onmessage=function(res){console.log(res);//打印MessageEvent对象console.log(res.data);//打印收到的消息};//在客户端Triggerws.onclose=function(evt){console.log("Connectionclosed.");};实现模板字符串解析描述:实现将模板字符串变量中的{{}}替换的功能。核心:使用字符串替换方法str.replace(regexp|substr,newSubStr|function)将字符串替换为正则匹配。实现:functionrender(template,data){//模板字符串正则性/\{\{(\w+)\}\}/,添加g作为全局匹配方式,每次匹配都会调用下面的函数letcomputed=template.replace(/\{\{(\w+)\}\}/g,function(match,key){//match:匹配子串;key:匹配字符串returndata[key];});returncomputed;}//testlettemplate="我是{{name}},年龄{{age}},性别{{sex}}";letdata={name:"张三",age:18}console.log(呈现(模板,数据));//我是张三,18岁,性别未定义常用CSS布局单位常用布局单位包括像素(px)、百分比(%)、em、rem、vw/vh。(1)像素(px)是页面布局的基础。一个像素表示终端(电脑、手机、平板等)屏幕上可以显示的最小区域。像素分为两种:CSS像素和物理像素:CSS像素:CSS中用于Web开发人员的抽象单位;物理像素:只与设备的硬件密度有关,任何设备的物理像素都是固定的。(2)百分比(%)。当浏览器的宽度或高度发生变化时,百分比单位可以使浏览器中组件的宽度和高度随着浏览器的变化而变化,从而达到响应式的效果。一般认为子元素的百分比是相对于直接父元素的。(3)em和rem比px更灵活。它们都是相对长度单位。它们的区别:em是相对于父元素的,rem是相对于根元素的。em:文本的相对长度单位。相对于当前对象中文本的字体大小。当前内联文本的字体大小如果没有手动设置,是相对于浏览器的默认字体大小(默认16px)。(相对于父元素的font-size的倍数)。rem:rem是CSS3添加的相对单位,是根元素(html元素)font-size的倍数。作用:可以使用Rem实现简单的响应式布局。可以使用html元素中的字体大小与屏幕的比例来设置font-size的值,这样当屏幕分辨率改变时元素也会随之改变。(4)vw/vh是与视窗相关的单位,vw表示相对于视窗的宽度,vh表示相对于视窗的高度。除了vw和vh之外,还有两个相关单位vmin和vmax。vw:相对于窗口的宽度,窗口的宽度为100vw;vh:相对于窗口的高度,窗口的高度为100vh;vmin:vw和vh中较小的值;vmax:vw和vh中的较大值;vw/vh和percentage很像,两者的区别:percentage(%):大部分是相对于祖先元素的,也有一些是相对于自身的,比如(border-radius,translate等)vw/vm:相对于窗口的大小,我们来说说for...in和for...of的区别?for...of遍历获取对象的键值,for...in获取对象的键名;for...in遍历整个对象原型链,性能很差,不推荐,而for...of只遍历当前对象,不遍历原型链;对于数组遍历,for...in会返回数组中所有可枚举属性(包括原型链可枚举属性),for...of只返回数组下标对应的属性值;总结:for...in循环主要是遍历对象,不是遍历数组;for....of循环可用于遍历数组、类数组对象、字符串、Sets、Maps和Generator对象。页面上有多个图像。HTTP的加载性能如何?在HTTP1下,浏览器对一个域名最多可以建立6个TCP连接,所以会请求多次。可以通过部署多个域名来解决。这样可以增加并发请求数,加快页面图片的获取速度。在HTTP2下,可以瞬间加载很多资源,因为HTTP2支持多路复用,可以在一个TCP连接中发送多个HTTP请求。new操作符的实现原理new操作符的执行过程:(1)首先创建一个新的空对象(2)设置原型,将对象的原型设置为函数的原型对象。(3)让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)(4)判断函数的返回值类型,如果是值类型,返回创建的目的。如果是引用类型,则返回该引用类型的对象。具体实现:functionobjectFactory(){letnewObject=null;让构造函数=Array.prototype.shift.call(arguments);让结果=空;//判断参数是否为函数if(typeofconstructor!=="function"){console.error("typeerror");返回;}//创建一个新的空对象,其原型为构造函数的原型对象newObject=Object.create(constructor.prototype);//指向新创建的对象,并执行函数result=constructor.apply(newObject,arguments);//判断返回对象letflag=result&&(typeofresult==="object"||typeofresult==="function");//判断返回结果返回标志?result:newObject;}//使用方法objectFactory(constructor,initializationparameters);arrayflattening数组扁平化就是将多层数组如[1,[2,[3]]]扁平化为一层[1,2,3]。使用Array.prototype.flat可以直接将多层数组扁平化为一层:[1,[2,[3]]].flat(2)//[1,2,3]现在是实现扁平化的效果。ES5实现:递归。functionflatten(arr){var结果=[];对于(vari=0,len=arr.length;iArray.isArray(项目))){arr=[].concat(...arr);}returnarr;}事件循环机制(EventLoop)事件循环机制告诉我们JavaScript代码整体的执行顺序。EventLoop即事件循环,是指一种浏览器或Node机制,解决javaScript单线程运行时无阻塞,也就是我们经常使用的异步原理。先执行脚本,再清空微任务队列,再开始下一轮事件循环,继续先执行宏任务,再清空微任务队列,以此类推。宏任务:Script/setTimeout/setInterval/setImmediate/I/O/UIRendering微任务:process.nextTick()/PromiseappealsetTimeout和setInterval都是任务源,真正进入任务队列的任务是他们分发的任务.优先级setTimeout=setInterval一个队列setTimeout>setImmediateprocess.nextTick>Promisefor(constmacroTaskofmacroTaskQueue){handleMacroTask();for(constmicroTaskofmicroTaskQueue){handleMicroTask(microTask);}}延迟加载的概念延迟加载也称为延迟加载、按需加载,是指在较长的网页中延迟加载图像数据,是一种较好的优化网页性能的方法。在一个比较长的网页或者应用中,如果图片比较多,加载完所有图片,用户只能看到可见窗口中的部分图片数据,比较浪费性能。如果使用图片的延迟加载,就可以解决上面的问题。可视区域之外的图片只有在屏幕滚动时才会加载,只有在屏幕滚动时才会加载。这使网页加载速度更快,并减少了服务器负载。懒加载适用于图片多、页面列表长(longlists)的场景。冒泡排序--时间复杂度n^2题目描述:实现一个冒泡排序,实现代码如下:functionbubbleSort(arr){//缓存数组长度constlen=arr.length;//外循环用于从头开始控制最后有多少轮比较+交换for(leti=0;iarr[j+1]){//交换两个[arr[j],arr[j+1]]=[arr[j+1],arr[j]];}}}//返回数组returnarr;}//console.log(bubbleSort([3,6,2,4,1]));为什么需要浏览器缓存?对于浏览器的缓存,主要是针对前端静态资源的。最好的效果是在发起请求后,拉取相应的静态资源存储在本地。如果服务器的静态资源没有更新过,那么下次请求直接从本地读取即可。如果服务器的静态资源已经更新,那么当我们再次请求时,我们会去服务器拉取新的资源并保存。本地。这大大减少了请求的数量,提高了网站的性能。这将使用浏览器的缓存策略。所谓浏览器缓存,就是浏览器将用户请求的静态资源存储在计算机的本地磁盘中。浏览器再次访问时,可以直接从本地加载,无需去服务器端请求。使用浏览器缓存有以下优点:减轻了服务器的负担,提高了网站的性能,加快了客户端网页的加载速度,减少了冗余的网络数据传输。Promise.all和Promise.race的区别(1)Promise.allPromise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值不同。成功时返回结果数组,失败时返回最先被拒绝的值。在Promise.all中,传入一个数组,返回一个数组,进行映射。传入的promise对象返回的值是按照顺序排列在数组中的,但是注意它们执行的顺序并不是按照Sequential的,除非iterable为空。需要注意的是,Promise.all获取到的成功结果数组中的数据顺序与Promise.all接收到的数组顺序是一致的,这样当发送多个请求,根据请求顺序,可以使用Promise.all来解决。(2)Promise.race,顾名思义,Promse.race的意思是race,意思是Promise.race([p1,p2,p3])中的结果,无论哪个结果很快得到,就返回那个结果,不管结果如何本身成功了还是失败了。当你想做某事时,你可以使用这个方法解决很久之后:Promise.race([promise1,timeOutPromise(5000)]).then(res=>{})将列表转换为树结构titledescription:[{id:1,text:'Node1',parentId:0//这里用0表示顶级节点},{id:2,text:'Node1_1',parentId:1//通过这个字段来判断孩子的parent}...]into[{id:1,text:'node1',parentId:0,children:[{id:2,text:'node1_1',parentId:1}]}]实现代码如下:functionlistToTree(data){lettemp={};让treeData=[];for(leti=0;i{if(Array.isArray(promises)){if(promises.length===0)returnresolve(promises);让result=[];让count=0;promises.forEach((item,index)=>{Promise.resolve(item).then(value=>{count++;result[index]={status:'fulfilled',value:价值};如果(count===promises.length)resolve(result);},reason=>{count++;result[index]={status:'rejected'.reason:reason};if(count===承诺。长度)解决(结果);});});}elsereturnreject(newTypeError("Argumentisnotiterable"));});}