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

前端面试题攻略

时间:2023-03-27 16:58:55 JavaScript

computedattributes和watches有什么区别?以及它们的应用场景?//computed计算属性的区别:依赖于其他属性值,而computed的值是缓存的,只有它所依赖的属性值发生变化,下次获取计算值时会重新计算计算值。watch监听器:更多用于观察,不做缓存,类似于一些数据的监听回调,每当监听到的数据发生变化,就会执行回调进行后续操作//应用场景需要进行数值计算,而当依赖其??他数据时,computed应该使用,因为可以利用computed的缓存属性,避免每次取值时都重新计算。当你需要在数据变化时执行异步或昂贵的操作时,你应该使用watch,使用watch选项允许异步操作(访问一个API),限制操作的执行频率,并在获得最终结果之前设置中间状态结果。这些是计算属性不能做的事情。如何根据设计稿适配移动端?移动端适配主要有两个维度:适配不同的像素密度,针对不同的像素密度使用CSS媒体查询,选择不同精度的图片保证图片不会失真;适配不同的屏幕尺寸,由于不同的屏幕尺寸有不同的逻辑像素大小,所以如果直接使用px作为开发单位,开发出来的页面在某款手机上会准确显示,但在另一款手机上会失真电话。为了适应不同屏幕的尺寸,设计稿的内容要按比例还原。为了使页面的大小自适应,可以使用rem、em、vw、vh等相对单位。JS数据类型基本类型:Number、Boolean、String、null、undefined、symbol(ES6新加入)、BigInt(ES2020)引用类型:Object、对象子类型(Array、Function)Vue通信1.props和$emit2。centraleventbusEventBus(基本不用)3.vuex(官方推荐状态管理器)4.当然还有$parent和$children的其他方法,但是基本不常用,或者使用起来太复杂.介绍通讯方式,还可以展开使用场景、使用方法、注意事项等。new一个构造函数,如果函数返回return{}、returnnull、return1、returntrue会发生什么?如果函数返回一个对象,那么new函数调用返回这个函数的返回对象,否则返回new创建的新对象。微任务包括:promise的回调,node中的process.nextTick,响应DomMutationObserver进行变化监听。宏任务包括:script脚本执行、setTimeout、setInterval、setImmediate等定时事件,以及I/O操作、UI渲染等。ES6新特性详解详见前端进阶面试题1.ES6引入了必须声明的严格模式变量和函数的参数不能有同名属性,否则报错不能和语句一起使用(说实话,我基本没用过)不能只读取属性赋值,否则一个error不能用前缀为0的八进制数表示,否则会报错(说实话,我基本没用过)不可删除的数据不能删除,否则一个error不能删除变量deleteprop会报错,只有属性deleteglobal[prop]eval不会在其外层作用域中引入变量evalandargumentscannotbereassignedarguments不会自动反映f的变化unction参数不能用arguments.caller(说实话我基本没用过)不能用arguments.callee(说实话我没用过)禁止this指向全局对象不能用fn。关于新增的let和const的变量声明3.变量的解构和赋值4.string的扩展includes():返回一个布尔值,表示是否找到参数字符串。startsWith():返回一个布尔值,表示参数字符串是否在原字符串的开头。endsWith():返回一个布尔值,表示参数字符串是否在原字符串的末尾。5.数值扩展Number.isFinite()用于检查数值是否有限。Number.isNaN()用于检查一个值是否为NaN。6.函数扩展函数参数指定默认值7.数组扩展扩展运算符8.对象扩展对象解构9.新的符号数据类型10.Set和Map数据结构ES6提供了新的数据结构Set。类似于数组,但是成员的值都是唯一的,没有重复值。Set本身是一个构造函数,用于生成一个Set数据结构。Map类似于对象,也是键值对的集合,但“键”的范围不限于字符串,各种类型的值(包括对象)都可以作为键。11.ProxyProxy可以理解为在目标对象之前设置了一层“拦截”。外部对对象的访问必须先经过这一层拦截。因此,提供了一种机制来过滤和重写外部访问。Proxy这个词的本意是代理,这里用它来表示它会“代理”某些操作,可以翻译为“代理”。Vue3.0使用proxy12.PromisePromise是异步编程的解决方案,比传统的解决方案——回调函数和事件更合理、更强大。特点是:对象的状态不受外界影响。状态一旦改变,就不会再改变,随时都可以得到这个结果。13、async函数与Generator函数的区别:(1)内置执行器。Generator函数的执行必须依赖executor,而async函数自带executor。也就是说,async函数的执行和普通函数完全一样,只有一行。(2)更好的语义。async和await的语义比星号和yield更清晰。async表示函数中有异步操作,await表示紧跟在后面的表达式需要等待结果。(3)一般情况下,await命令后面跟着一个Promise对象。如果不是,它将变成一个立即解析的Promise对象。(4)返回值为Promise。async函数的返回值是一个Promise对象,这比Generator函数的返回值是一个Iterator对象要方便的多。您可以使用then方法指定下一步操作。14.Class类和let、const一样:没有变量提升,没有重复声明...ES6类可以看成只是一个语法糖,它的大部分功能都可以用ES5这种新的类写法来实现只是让对象原型写的更清晰,更像面向对象编程的语法。15.ModuleES6模块自动采用严格模式,不管你是否加“usestrict”;是否到模块头。导入导出命令与导出导出默认代码输出的区别varlength=10;functionfn(){console.log(this.length);}varobj={length:5,method:function(fn){fn();参数[0]();}};obj.method(fn,1);输出结果:102分析:第一次执行fn(),this指向window对象,输出10。第二次执行arguments[0]相当于调用带参数的方法,this指向参数,并且这里传递了两个参数,所以输出参数的长度为2。代码输出结果Promise.reject('err!!!').then((res)=>{console.log('success',res)},(err)=>{console.log('error',err)}).catch(err=>{console.log('catch',err)})输出如下:errorerr!!!我们知道.then函数中有两个参数:第一个参数是用来处理Promise成功的函数,第二个是处理失败的函数。也就是说Promise.resolve('1')的值会进入成功的函数,Promise.reject('2')的值会进入失败的函数。在这道题中,错误直接被then的第二个参数捕获,所以不会被catch捕获,输出结果为:errorerr!!!'但是,如果像下面这样:Promise.resolve().then(functionsuccess(res){thrownewError('error!!!')},functionfail1(err){console.log('fail1',err)}).catch(functionfail2(err){console.log('fail2',err)})then的第一个参数抛出错误,那么他不会被第二个参数去激活,而是被后面的catch捕获。事件委托的理解(一)事件委托的概念事件委托本质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,父节点可以通过事件对象获取目标节点,所以可以在父节点上定义子节点的监听函数,子节点的监听函数父节点会统一处理多个子元素的事件,这种方式称为事件委托(eventproxy)。使用事件委托消除了将监听事件绑定到每个子元素的需要,从而减少了内存消耗。并且使用事件代理还可以实现事件的动态绑定。比如新增一个子节点,不需要单独为其添加监听事件。它绑定的事件会交给父元素中的监听函数处理。(2)事件委托的特点减少了内存消耗。如果有一个包含大量列表项的列表,当列表项被点击时需要响应一个事件:

  • item1
  • item2
  • item3
  • ......
  • itemn
  • 如果把每个列表项一个一个绑定一个函数,内存消耗很大,消耗很大效率方面的表现。所以更好的办法是把这个点击事件绑定到它的父层,也就是ul,然后在执行事件的时候匹配判断目标元素,这样事件委托可以减少很多内存消耗,节省效率。动态绑定事件绑定到上面例子中的每个列表项。很多时候需要通过AJAX或者用户操作来动态添加或者删除列表项元素,所以每次变化都需要重新添加。元素绑定事件,为即将删除的元素解除绑定事件;如果使用事件委托就没有这样的麻烦,因为事件是绑定在父层上的,与目标元素的增减无关。Execute目标元素是在实际响应事件函数执行的过程中匹配的,所以在动态绑定事件的情况下使用事件可以减少很多重复性的工作。//实现#list下的li元素对其父层元素即#list的事件委托://给父层元素绑定事件document.getElementById('list').addEventListener('click',function(e){//兼容性处理varevent=e||window.event;vartarget=event.target||event.srcElement;//判断是否匹配目标元素if(target.nodeName.toLocaleLowerCase==='li'){console.log('内容为:',target.innerHTML);}});上面代码中,target元素是#list元素下被点击的元素,然后判断target的一些属性(如:nodeName、id等)可以更精准的匹配到某类#listli元素;(3)局限性当然,事件委托也有局限性。比如focus、blur等事件没有事件冒泡机制,无法实现事件委托;mousemove、mouseout等事件,虽然有事件冒泡,但只能通过position不断计算定位,消耗性能高,所以也不适合做事件委托。当然,事件委托不仅有优点,也有缺点。事件委托会影响页面性能。主要影响因素有:元素中绑定事件委托的数量;底部元素被点击,绑定事件元素之间的DOM层数;必须使用事件委托的地方,可以做如下处理:只在需要的地方使用事件委托,例如:ajax的局部刷新区域,最小化绑定层级,不绑定在body元素上,减少绑定次数.如果可能,将多个事件的绑定合并为一个事件委托,通过该事件委托的回调进行分发。用过TypeScript吗?它有什么作用?为JS添加类型支持,提供对最新版ES语法的支持,有利于团队协作和故障排除,开发大型项目代码输出结果constpromise1=newPromise((resolve,reject)=>{setTimeout(()=>{resolve('success')},1000)})constpromise2=promise1.then(()=>{thrownewError('error!!!')})console.log('promise1',promise1)console.log('promise2',promise2)setTimeout(()=>{console.log('promise1',promise1)console.log('promise2',promise2)},2000)输出结果如下:promise1Promise{}promise2Promise{}Uncaught(inpromise)Error:error!!!promise1Promise{:"success"}promise2Promise{:Error:error!!}正向代理与反向代理不同的是正向代理:客户端想获取某个服务器的数据,但由于各种原因无法直接获取。于是客户端设置代理服务器并指定目标服务器,然后代理服务器将请求转发给目标服务器,并将获取到的内容发送给客户端。这本质上是为了将真实客户端从真实服务器中隐藏起来。实现正向代理需要修改客户端,比如修改浏览器配置。反向代理:为了提高网站性能(负载均衡),通过将工作负载分到多个服务器上,服务器在收到请求时会先根据转发规则判断将请求转发到哪个服务器,然后转发请求到对应的真实服务器。这本质上是为了向客户端隐藏真实服务器。一般使用反向代理后,需要修改DNS,将域名解析到代理服务器IP。此时浏览器无法检测到真实服务器的存在,当然也不需要修改配置。正向代理和反向代理的结构相同,都是客户端-代理-服务器结构。它们之间的主要区别在于哪一方在中间设置代理。在正向代理中,代理由客户端设置,隐藏客户端;而在反向代理中,代理由服务器设置以隐藏服务器。什么是内联元素?什么是块级元素?什么是空(void)元素?行内元素包括:abspanimginputselectstrong;块级元素包括:divulollidldtddh1h2h3h4h5h6p;空元素,即没有内容的HTML元素。空元素在开始标签中关闭,即空元素没有结束标签:常见的有:

    ;罕见的是:、、、。说说SPA单页有什么优缺点?优点:1.体验好,无刷新,减少请求数据ajax异步获取页面流程;2、前后端分离3、减轻服务器压力4、共享一套后台程序代码,适配多终端缺点:1、首屏加载太慢;2、SEO不利于搜索引擎抓取。告诉我如何获得数组中最多的项目?//我这里只是一个例子constd={};letary=['赵','钱','孙','孙','李','周','李','周','周','李'];ary.forEach(k=>!d[k]?d[k]=1:d[k]++);constresult=Object.keys(d).sort((a,b)=>d[b]-d[a]).filter((k,i,l)=>d[k]===d[l[0]]);console.log(result)代码输出constpromise=newPromise((resolve,reject)=>{console.log(1);console.log(2);});promise.then(()=>{console.log(3);});console.log(4);输出结果如下:124promise.then是一个microtask,在所有macrotask执行完后执行,promise里面的state需要change,因为这里没有发生内部变化,一直处于pending状态,所以不输出3。代码输出vara=10varobj={a:20,say:()=>{console.log(this.a)}}obj.say()varanotherObj={a:30}obj.say.apply(anotherObj)输出结果:1010我怎么知道箭头函数没有绑定this,它的this来自上下文它的父节点所在的位置,因此将首先打印全局10中a的值。虽然后面让say方法指向了另一个对象,但是箭头函数的特性是无法改变的。它的this仍然指向全局,所以10仍然会输出。但是,如果是普通函数,那么就会有完全不同的结果:vara=10varobj={a:20,say(){console.log(this.a)}}obj.say()varanotherObj={a:30}obj.say.apply(anotherObj)outputresult:2030这时候say方法中的this会指向它所在的对象,输出其中的a的值。闭包先解释什么是闭包。闭包是简单嵌套的函数。内层函数引用外层函数的变量,导致垃圾回收机制不回收当前变量。这样的操作会带来内存泄漏。影响,当内存泄漏到一定程度,就会影响你的项目运行,卡死等等。因此,我们应该尽量避免项目中的内存泄漏。原型构造函数是一种特殊方法,主要用于在对象创建时对其进行初始化。每个构造函数都有一个原型(prototype)(箭头函数而Function.prototype.bind()没有)属性,这个原型(prototype)属性是一个指向对象的指针,这个对象的目的是包含一个特定对象的所有实例typeSharedpropertiesandmethods,即这个原型对象用于共享实例对象的属性和方法。每个实例对象的__proto__指向这个构造函数/类的原型属性。面向对象三大特性:继承/多态/封装关于new操作符:1.new执行的函数,函数内部默认生成一个对象2.函数内部的this指向这个new生成的对象默认情况下3.新执行函数生成的对象是函数的默认返回值ES5例子:functionPerson(obj){this.name=obj.namethis.age=obj.age}//prototypemethodPerson.prototype.say=function(){console.log('Hello,',this.name)}//p为实例化对象,newPerson()的操作调用构造函数的实例化letp=newPerson({name:'Tomato',age:'27'})console.log(p.name,p.age)p.say()ES6例子:classPerson{constructor(obj){this.name=obj.namethis.age=obj.age}say(){console.log(this.name)}}letp=newPerson({name:'ES6-Tomato',age:'27'})console.log(p.name,p.age)p.say()