2022前端面试题整理

1. cookie sessinonStorage localStorage

得分点:
数据存储位置、生命周期、存储大小、写入方式、数据共享、发送请求时是否携带、应用场景

标准回答:
cookie、sessionStorage、localStorage都是浏览器的本地存储
共同点: 都是存储在浏览器本地
区别:cookie是由服务端写入的, 而sessionStorage、localStorage都是由前端写入的,
cookie的生命周期是由服务端写入的时候就设置好的,localStorage是写入就一直存在,除非手动清除,sessionStorage是页面关闭就会自动清除,
cookie的存储空间比较小,大概4KB,sessionStorage和loaclStorage的存储空间比较大,大概5M,
cookie、sessionStorage、localStorage数据共享都遵循同源原则,sessionStorage还限制必须同一个页面,
在前端给后端发送请求会自动携带cookie中的数据,但是sessionStorage、localStorage不会,
应用场景不同:cookie一般用于存储登录验证信息,sessionId或者token。localStorage常用于存储不易变动的数据,减轻服务器压力,sessionStorage可以用来检测用户是否刷新进入页面


2. js的数据类型

得分点:
number、string、boolean、bigint、symbol、null、undefined、Object 8种

标准回答:
js的数据类型分为两类,一类是基本数据类型也叫简单数据类型,包含7种类型:number、string、boolean、bigInt、symbol、null、undefined,另一类是引用数据类型也叫复杂数据类型,通常用object代表,普通对象,数组、正则、日期,Math数据函数都属于object
数据分成两大类的本质区别:基本数据类型和引用数据类型他们在内存种的存储与方式不同,基本数据类型是直接存在栈中的简单数据段,占用空间小,属于被频繁使用的数据、引用数据类型是存储在内存中,占用空间大,引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始位置、当解释器寻找引用值时、会检索其在栈中的地址,取得地址后从堆中获得实体
symbol是Es6新出的一种数据类型,这种数据类型的特点就是没有重复的数据,可以用为object的key、数据的创建方法是symbol(),因为它的构造函数不够完整,所以不能使用new Symbol()创建数据。由于symbol()创建数据具有唯一性,所以symbol() !== symbol(), 同时使用symbol数据作为key,不能使用for获取到这个key,需要使用object.getOwnPropertySymbols(obj) 获取这个obj对象中key类型是symbol的key
bigInt也是es6新出的一种数据类型,这种数据类型的特点就是数据涵盖的范围大,能够解除超出普通数据类型范围报错的问题
number精度范围是2的52次方位


3. 闭包

得分点:
变量背包、作用域链、局部变量不销毁、函数体外访问函数的内部变量、内存泄露、内存溢出、形成块级作用域、柯里化、构造函数中定义特权方法、Vue种数据响应式Observer

标准回答:
闭包: 一个函数和词法环境的引用捆绑在一起,这样的组合就是闭包,
一般就是一个函数A,return其内部的函数B, 被return出去的B函数能够在外部访问A函数内部的变量,这时候就形成了一个B函数的变量背包,A函数执行结束后这个变量背包也不会被销毁,并且这个变量背包在A函数外部只能通关B函数访问,
闭包形成的原理:作用域链,当前作用域可以访问上级作用域中的变量,闭包解决的问题: 由于垃圾回收器不会将闭包中的变量销毁,于是就造成了内存泄露,内存泄漏积累多了就容易导致内存溢出,

加分回答:闭包的应用,能够模仿块级作用域,能够实现柯里化、在构造函数中定义特权方法,Vue种数据响应式Observer中使用闭包等


4.promise

得分点:
pending、rejected、resolved、微任务、then、catch、Promise.resolve()、promise.reject()、promise.all()、promise.any() promise.race();

标准回答:
promise的作用:promise是异步微任务,解决了异步多层嵌套回调的问题,让代码的可读性更高,更容易维护
promise的使用: promise是ES6提供的一个构造函数,可以使用promise构造函数new一个实例,promise构造函数接受一个函数作为参数,这个函数又两个参数,分别是‘resolve’和‘reject’,‘resolve’将promise由等待pending变为成功,将异步操作的结果作为参数传递过去,‘reject’则将状态由等待pending变成失败,在异步操作失败时调用,将异步操作报出的错误作为参数传递过去。
实例创建完成后,可以使用'then'方法分别指定成功或失败的回调函数,可以使用catch捕捉失败。
then和catch最终返回的也是一个promise,所以可以链式调用,
promise的特点:1. 对象的状态不受外界影响,promise对象代表一个异步操作,有三种状态, pending(执行中) resolved(成功,又称fulfilled)。rejected(拒接),pending为初始状态。resolved和rejected为结束状态,结束状态代表promise生命周期已结束。2.一旦状态改变,就不会在变,任何时候都可以得到这个结果, promise对象的状态改变,只能有两个可能, 从pending变为resolved | 从pending变成rejected。3.resolve方法的参数是then中回调函数的参数,reject方法种的参数是catch中的参数 4. then方法和catch方法只要不报错,返回的都是一个fulfilled状态的promise

加分回答:
promise.resolve() 返回的promise对象状态变成fulfilled。并且将value传递给对应的then方法。
promise.reject() 返回一个状态为失败状态的promise对象,并将给定的失败信息传递给对应的处理方法。
promise.all() 返回一个新的promise对象,该promise对象的参数对象里面所有的promise对象都成功的时候才会触发,一旦有任何一个promise对象失败则立即触发该promise对象的失败。
promise.any() 接受一个promise对象的集合,当其中一个promise成功,就返回那个成功的promise的值。
promise.race() 当参数里面的任意一个promise对象成功或者失败后,父promise马上也会用子promise的成功返回或者失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象


5.跨域

得分点:
同源协议、协议、域名、端口、CORS、node中间件、JSONP、postmessage

标准回答:
跨域:当前页面中的某个接口请求的地址和当前页面的地址如果协议、域名、端口其中有一项不同,该接口就跨域了
跨域限制的原因:浏览器为了保证网页的安全,出的同源协议策略
跨域解决方案:1. CORS: 目前最常用的一种解决办法,通过设置后端允许跨域、 2. node中间件、nginx反向代理:跨域限制的时候浏览器不能访问跨域服务器,node中间件和nginx反向代理,都是让请求发给代理服务器,静态页面和代理服务器是同源的,然后代理服务器在向后台服务器发送请求,服务器和服务器之间不存在同源限制 3.JSONP 利用原理是script标签可以跨域请求资源,将回调函数作为参数拼接在url后,后端收到请求,调用该回调函数,并将数据作为参数返回去,注意设置响应头返回文档类型,应该设置成JavaScript


6.vuex

得分点: state、mutations、getters、action、module、store.commit、store.dispatch

标准回答:
Vuex是集中管理项目公共数据的。
vuex有state、mutations、getters、actions、module属性
state属性用来存储公共管理的数据。
mutations属性定义改变state中数据的方法。注意:不要在mutation中的方法中写异步的ajax,那样数据就不可跟踪了
getters属性可以认为是定义store中的计算属性、就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当他的依赖值发生了改变才会被重新计算,
action属性类似于mutation。不同在于:action提交的是mutation。而不是直接改变数据状态。action可以包含任何的异步操作。
moudle属性是将store分割成模块,每个模块拥有自己的state、mutation、action、getter甚至是嵌套子模块,从上至下进行同样的方式分割,
使用方法:
state直接以对象方式添加属性
mutations: 通过store.commit调用
action:通过store.dispath方法触发
getters: 直接通过store.getters调用

加分回答: 可以使用mapState、mapMutations、mapActions、mapGetters一次性获取每个属性下对应的多个方法。vuex在大型项目中比较常用,非关系组件传递数据比较方便


7.数据去重

得分点: 对象属性、new Set()、indexOf、hasOwnproperty、reduce+includes、filter

利用对象属性key排除重复项: 遍历数组,每次判断对象中是否存在该属性。不存在就存储在新数组中、并且把数组元素作为key,设置一个值。存储在对象中,最后返回新数组,这个方法效率高,缺点占用较多空间,使用的额外空间有一个查询对象和一个新数组
利用set类型数据无重复项: new 一个set。参数为需要去重的数据。set会自动删除重复的元素,再将set转为数组返回,这个方法的优点:效率更高,代码简单、思路清晰、缺点:可能有兼容性问题
filter+indexOf。这个方法和第一种方法类似,利用array自带的filter方法,返回arr.indexOf(num)等于index的num,原理是indexOf会返回最先找到的数字索引,优点:可以在去重的时候插入对元素的操作,可扩展性强
reduce+includes去重:这个方法就是利用reduce遍历和传入一个空数组作为去重后的数组,然后内部判断新数组中是否存在当前遍历的元素,不存在就插入到新数组中,这个方法消耗多,内存也有额外占用,方法还有很多,常用这些

加分回答:在数据低于10000条的时候没有明显的差别,高于1w条的,利用对象属性和set方法时间消耗最少,后面两条的时间消耗较多,由于key方法内存空间消耗比较多,且现在很多项目不考虑低版本浏览器的兼容性问题,建议使用set方法,简洁方便


8. vue2双向绑定的原理和缺陷

得分点:
Object.defineProperty、getter、setter
标准回答:Vue响应式指的是: 组件的data发生变化,立即触发视图的更新
原理:
Vue采用数据劫持 结合 发布者-订阅者的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的getter、setter,在数据变动时发布消息给订阅者,订阅者收到消息后进行相应的处理,通过原生js提供的监听数据的API,当数据发生变化的时候,在回调函数中修改DOM。 核心API:Object.dedineproperty
缺点:
一次性递归到底开销很大,如果数据很大,大量的递归导致调用栈溢出、 不能监听对象的新增属性和删除属性 无法正确的监听数组的方法


9.vue2和vue3的区别

vue2不管数据多大,都会在一开始就为其创建观察者,当数据很大时,这可能会在页面载入时造成明显的性能压力,vue3只会对被用于渲染初始可见部分的数据创建观察者,而且vue3的观察者更高效
object.defineProperty无法监听到新增和删除属性,但是proxy可以监听到
object.defineProperty需要遍历对象每个数据,对性能影响,proxy监控对象本身


10.ES6的箭头函数

得分点:
没有this、this是从外部获取、不能使用new、没有arguments、没有原型和super

标准回答:箭头函数相当于匿名函数,简化了函数定义。箭头函数有两种写法,当函数体是单条语句的时候可以省略{}和return,另一种是多条语句,不可以省略{}和return,
箭头函数最大的他特点就是没有this。所以this是从外部获取,就是继承外部的执行上下文中的this。由于没有this关键字,所以箭头函数也不能作为构造函数。同时通关call() 或者apply() 方法调用一个函数是,只能传递参数,不能绑定this,第一个参数会被忽略,箭头函数也没有原型和super


11. call apply bind的作用和区别

得分点:
bind改变this指向不直接调用、call和apply改变this指向直接调用、apply接受第二个参数为数组、call用于对象的继承、伪数组转化为真数组、apply用于找出数组中的最大值和最小值以及数组合并,bind用于vue改变函数的this指向

标准回答:
call、apply、bind的作用都是改变函数运行时的this指向,bind和call、apply在使用上有所不同、bind在改变this指向返回一个改变执行上下文的函数。不会立即执行函数,需要调用函数的时候在调用
但是call和apply在改变this指向的通时执行了该函数,call和apply接收多个参数,第一个参数都是this指向的上下文,后面的参数都是作为改变this指向的函数的参数。
call和apply的参数格式不同,call时一个参数对应一个原函数的参数,但是apply第二个参数时数组,数组中每个元素代表函数接口的参数,数组有几个元素函数就接受几个参数


12.HTML语义化

得分点:语义化标签、利于页面内容结构化、利于无css页面可读、利于SEO、利于代码可读

标准回答:HTML语义化比就是指在使用HTML标签构建页面时,避免大幅度的使用无语义的标签,语义标签:header footer h1-h6 p br


13. this指向

得分点: 全局执行上下文、函数执行上下文、this严格模式undefined、非严格模式window、构造函数新对象本身、普通函数不继承this、箭头函数无this

标准回答:
this关键字的由来: 在对象内部的方法中使用对象内部的属性是一个普遍的需求,但是javascript的作用域机制并不支持这一点,基于这个需求,javascript又搞出来一套this机制,this存在场景有三种,全局执行上下文和函数执行上下文和eval执行上下文(暂不讨论),
在全局执行环境中无论是否在严格模式下,this都是指向全局对象,在函数执行上下文中访问this,函数的调用方式决定了this的值,在全局环境中调用一个函数,函数内部的this指向的是全局变量window,通关一个对象来调用其内部的一个方法,该方法的执行上下文中的this指向对象本身,
普通函数this指向:当函数被正常调用时,在严格模式下this指向undefined,非严格模式下this指向的是全局对象window,通过一个对象来调用其内部的一个方法,该方法的执行上下文中的this指向对象本身。new 关键字构架好了一个新对象,并且构造函数的this其实就是新对象本身。
嵌套函数的this不会继承外层函数的this。箭头函数没有this,箭头函数并不会创建自身的执行上下文,所以箭头函数中的this取决于它的外部函数

加分回答: 箭头函数没有this。所以也不能作为构造函数,但是需要继承函数外部的this时,使用箭头函数比较方便


14.css尺寸单位

得分点:px、rem、em、vw、vh
标准回答:
px绝对长度单位,它的大小取决于屏幕的分辨率,是开发网页中常常使用的单位
em相对长度单位,在font-size中使用相对于父元素的字体大小,在其他属性中使用相对自身的字体大小
rem 相对长度单位 根据根元素的字体大小,如果根元素未设置,使用浏览器默认字体大小
vw,vh相对长度单位,相对与视窗宽度的1%


15.js变量提升

得分点: var声明的变量提升、函数声明提升、let和const变量不提示

标准回答:
变量提升是指js的变量和函数声明会在代码编译期提升到代码的最前面,变量提升成立的前提是使用var关键字进行声明的变量,并且变量提升的时候只有声明被提升,赋值并不会被提升,同时函数的声明提升会比变量的提升优先,变量提升的结果,可以在变量初始化之前访问该变量,返回的是undefined。在函数声明前可以调用该函数

加分回答: 使用let 和const声明的变量是创建提升,形成暂时性死区,在初始化之前访问let和const创建的变量会报错


16.hashRouter和HistoryRouter的区别和原理

得分点:
window.onhashChange history.pushState window.onpopstate

标准回答:
history和hash都是利用浏览器的两种特性实现的前端路由
history是利用浏览器历史记录栈的api实现,hash是监听loaction对象的hash值变化事件来实现
history没有#号,hash有#号,相同的url, history会触发添加到浏览器历史记录栈中,hash不会触发
history需要后端配合,在做进一步处理,如果后端不配合,会出现404,hash不需要
history原理 通过history.pushstate使用它做页面跳转不会触发页面刷新,使用window.onpopstate监听浏览器的前进和后退,在做其他处理

加分回答: hash模式下有#号,需要url更加优雅时,可以使用history模式,需要兼容低版本浏览器时建议使用hash模式


17.map和forEach的区别

得分点:map创建新数组,map返回处理后的值、forEach不修改原数组、forEach方法返回undfined

标准回答:
map有返回值、可以开辟新空间,return出来一个length和原数组一致的数组,即便数组元素是undefined或者null。
forEach默认无返回值。返回结果为undfined。可以通过在函数体内部使用索引改变数组元素

加分回答:map的处理速度比forEach快,。而且返回一个新数组,方便链式调用数组的其他方法


18.事件循环Event loop, 宏任务、微任务

得分点:任务挂起、同步任务执行结束执行队列中的异步任务、执行script标签内部代码、setTimeout/setInterval、ajax请求、postMessage。promise、nextTick

标准回答:
浏览器的事件循环:执行js代码的时候,遇见同步任务,直接推入调用栈中执行,遇到异步任务,将该任务挂起,等到异步任务有返回之后推入任务队列中,当调用栈中的同步任务全部执行完成,将任务队列中的任务按顺序一个个推入执行,重复执行这一系列的行为, 异步任务又分为宏任务和微任务。
宏任务: 任务队列中的任务称为宏任务,每个宏任务都包含一个微任务队列
微任务: 等宏任务中的主要功能都完成后,渲染殷勤不急着去执行下一个宏任务,而是执行当前宏任务中的微任务
宏任务包括:执行script标签内部代码、setTimeout、ajax请求
微任务包括:pormise、MutonObserver、Object.observer


19. vue3实现数据双向绑定的方法

得分点:proxy、数据拦截、劫持整个对象、返回一个新对象

标准回答:
vue3通过proxy实现数据的双向绑定。
proxy是ES6中新增的一个特性、实现的过程是在目标对象之前设置了一层拦截。外界对该对象的访问,都必须先通关这层拦截、因此提供了一种机制,可以对外界的访问进行过滤和改写
用法:ES6提供的proxy构建函数、用来生成proxy实例,var proxy = new proxy(targer, hanler)
target:是用于proxy包装的被代理对象(可以是任何类型的对象,包括原生数组、函数甚至另一个代理)
handler:是一个对象,其声明了代理target的一些操作,其属性是当执行一个操作时定义代理的行为的函数

加分回答:
object.defineproperty的问题:在vue中,object.defineProperty无法监控数组下标的变化,导致直接通过数组下标给数组设置值,不能实时响应。vue2里面是通过递归以及遍历data对象来实现对数据的监控,如果属性值也是对象,那么需要深度遍历,显然如果能劫持整个对象,不管是对操作还是性能都会有很大提升
proxy的有点,劫持整个对象,并返回一个新对象

你可能感兴趣的:(2022前端面试题整理)