Web面试题汇总-自用

目录

1、cookie、localStorage、sessionStorage

1.1区别

1.2cookie优点

1.3cookie的缺点

2.js数据类型及区别

2.1js数据类型分为两类

2.2区别

3.对闭包的理解

3.1概念

3.2闭包形成的原理

3.3闭包带来的问题

3.4闭包的应用

4.promise

4.1promise的作用

4.2promise的使用

4.3promise的特点

4.4手写promise

5.跨域

5.1跨域概念

5.2跨域解决方案

5.3跨域场景

6.BFC

6.1概念

6.2布局规则

6.3形成条件

7.Vuex

7.1是什么

7.2属性的作用

7.3如何使用

8.js有几种方法判断变量的类型

9.CSS样式优先级规则

10.js实现异步的方法

11.Vue2.0双向绑定原理与缺陷

12.数组去重的方法

13.null和undefined的区别,如何让一个属性变为null

14.CSS的浮动

15.es6箭头函数

16.call、apply、bind的作用和区别

17、this指向(普通函数、箭头函数)

18.CSS尺寸设置的单位

19.元素水平垂直居中的方法

20.js变量提升

21.HashRouter和HistoryRouter的区别和原理

22.map和forEach的区别

23.事件循环Event loop,宏任务与微任务

24.Vue3.0实现数据双向绑定的方法

25.Diff算法

26.三栏布局的实现方案

27.浏览器垃圾回收机制

28.Vue的keep-alive

29.CSRF攻击是什么

30.XSS攻击是什么

31.js继承的方法和优缺点

32.defer和async的区别

33.浏览器如何渲染页面的

34.computed和watch的区别和运用场景

35.Vue中$nextTick的作用与原理

36.new一下会发生什么

37.token能放在cookie中吗

38.浏览器输入URL发生了什么

39.Vue组件通信的方式

40.v-if和v-show的区别

41.什么是MVVM

42.对SPA单页面的理解它的优缺点是什么

43.什么是盒子模型

44.怎样理解Vue的单项数据流

45.Vue的父组件和子组件生命周期


1、cookie、localStorage、sessionStorage

1.1区别

  1. cookie是由服务器端写入的,而sessionStorage、localStorage是由前端写入的;
  2. cookie的生命周期是由服务器端在写入的时候就设定好的,localStorage是写入就一直存在,除非手动删除,sessionStorage是页面关闭的时候就会自动清除;
  3. cookie的存储空间比较小不超过4k,localStorage、sessionStorage的存储空间相对而言要大很多可以达到5M;
  4. cookie、localStorage、sessionStorage数据共享都遵循同源原则,sessionStorage还限制必须是同一个页面;
  5. 在前端给后端发送请求的时候会自动携带cookie中的数据,但是sessionStorage、localStorage不会。

1.2cookie优点

  1. 数据持久性;
  2. 不需要任何服务器资源。cookie存储在客户端并在发送后由服务器读取;
  3. 可配置到期规则。控制cookie的生命周期,使之不会永远有效,偷盗者很可能拿到一个过期的cookie;
  4. 简单性。基于文本的轻量结构;
  5. 通过良好的编程。控制保存在cookie中session对象的大小;
  6. 通过加密和安全传输技术(SSL),减少cookie被破解的可能性;
  7. 只在cookie中存放不敏感数据,即使被盗也不会产生重大损失。

1.3cookie的缺点

  1. cookie数量和长度的限制
    1. 数量:每个域的cookie总数有限。
      1. IE6或更低版本最多20个cookie;
      2. IE7及之后的版本最多50个cookie;
      3. Firefox最多50个cookie;
      4. Chrome和Safari没有做硬性限制。
    2. 长度:每个cookie的长度不超过4k,否则会被截掉。
  2. 潜在的安全风险。cookie可能被拦截、篡改。如果cookie被拦截,就有可能取得所有的session信息;
  3. 用户配置未禁用。有些用户禁用了浏览器或客户端设备接受cookie的能力;
  4. 有些状态不可能保存在客户端。例如:为了防止重复提交表单,我们需要在服务器端保存一个计数器。如果我们把这个计数器保存在客户端,那么它起不到任何作用。

2.js数据类型及区别

2.1js数据类型分为两类

一类是基本数据类型,也叫简单数据类型,包含7种分别是:Number、String、Boolean、null、undefined、BigInt、Symbol(Symbol和BigInt是ES6新出的数据类型,其中BigInt的特点是数据涵盖的范围大,能够解决超出普通数据类型范围报错的问题;Symbol的特点是没有重复的数据,可以作为object的key)。

一类是引用数据类型,也叫复杂数据类型,通常用Object代表,像我们经常用的对象、函数、数组、正则、日期等都属于Object。

2.2区别

本质上的区别是它们在内存中的存储方式不同。基本数据类型是直接存储在栈中,属于被频繁使用的数据;引用数据类型是存在在堆内存中,在栈里面存储了指针,该指针指向堆内存中该实体的一个起始地址,当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得该实体。

3.对闭包的理解

3.1概念

一个函数对周围状态的引用捆绑在一起,内层函数可以访问到其外层函数的作用域,外层函数也可以访问到内层函数的作用域。

3.2闭包形成的原理

相当于一个作用域链,当前作用域可以访问上级作用域中的变量

3.3闭包带来的问题

由于垃圾回收器不会将闭包中的变量销毁,于是就造成了内存泄漏,内存泄漏积累多了容易导致内存溢出。

内存泄漏(memory leak):  是指程序在申请内存后,无法释放已申请的内存空间,导致系统无法及时回收内存并且分配给其他进程使用。

内存溢出(out of memory):指程序申请内存时,没有足够的内存供申请者使用,导致数据无法正常存储到内存中。

3.4闭包的应用

能够模仿块级作用域,实现数据的一个私有化。

4.promise

4.1promise的作用

promise是异步微任务,解决了异步多层嵌套回调的问题,让代码的可读性更高,更容易维护。

4.2promise的使用

promise是ES6提供的一个构造函数,可以使用promise构造函数new一个实例,promise构造函数接收一个函数作为参数,这个函数有两个参数,分别是 ‘resolve’ 和 ‘reject’,resolve将promise的状态由等待变为成功,将异步操作的结果作为参数传递过去;reject则将状态由等待转变为失败,在异步操作失败时调用,将异步操作报出的错误作为参数传递过去。实例创建完成后,可以使用 ‘then’ 方法分别指定成功或失败的回调函数,也可以使用catch捕获失败,then和catch最终返回的也是一个promise。所以可以链式调用。

4.3promise的特点

  1. 对象的状态不受外界影响(promise对象代表一个异步操作,有三种状态)pending(执行中),resolved(成功),rejected(拒绝)。其中pending为初始状态,resolved和rejected为结束状态(结束状态表示promise的生命周期已结束)
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。promis对象的状态改变只有两种可能(状态凝固了,就不会再变了,会一直保持这个结果):从pending变为resolved  从pending变为rejected
  3. resolve方法的参数是then中回调函数的参数,reject方法中的参数是catch中的参数
  4. then方法和catch方法只要不报错,返回的都是一个resolved状态的promise。

4.4手写promise

//执行器函数先执行(同步任务),再new Promise(),启动异步任务
const p = new Promise((resolve, reject) => {
    //异步函数
    setTimeout(() => {
        if(Date.now()%2 == 0) {
            resolve('成功')
        } else {
            reject('失败')
        }
    }, 1000);
})
p.then(
    //这里的value是从异步函数中获取到的成功的返回值
    (value) => {
    console.log(value);
    }, 
    //这里的reason是从异步函数中获取到的失败的原因
    (reason) => {
    console.log(reason)
    }
)

5.跨域

5.1跨域概念

当前页面中的某个接口请求的地址和当前页面的地址如果协议、域名、端口其中有一项不同,就说该接口跨域了

5.2跨域解决方案

  1. cors:目前最常用的一种解决办法,通过设置后端允许跨域实现。
  2. res.setHeader('Access-Control-Allow-Origin', '*')
  3. res.setHeader(''Access-Control-Allow-Methods'', ''GET, PUT, OPTIONS, POST'')
  4. node中间件:就是让请求发送给代理服务器,静态页面和代理服务器是同源的,然后代理服务器再向后端服务器发送请求,服务器和服务器之间不存在同源限制
  5. JSONP:利用script标签来实现跨域请求资源,将回调函数作为参数拼接在url中。后端收到请求,调用该回调函数,并将数据作为参数返回去
  6. postmessage:通过发送和接收API实现跨域通信。

5.3跨域场景

前后端分离式开发、调用第三方接口

6.BFC

6.1概念

BFC(Block Formatting Context)块级格式化上下文,是Web页面一块独立的渲染区域,内部元素的渲染不会影响边界以外的元素。

6.2布局规则

  1. 内部盒子会在垂直方向,一个接一个地放置
  2. Box垂直方向的距离有margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
  3. 每个盒子(块盒与行盒)的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
  4. BFC的区域不会与float box重叠。
  5. BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之也是如此。
  6. 计算BFC的高度时,浮动元素也参与计算。

6.3形成条件

  1. float设置成left或right
  2. position是absolute或者fixed
  3. overflow不是visible,是auto、scroll、hidden
  4. display是flex或者inline-block等

BFC的方式都能清楚浮动,但是常用的清除浮动的BFC方式只有overflow:hidden,因为使用float或者position方式清除浮动,虽然父级盒子内部浮动被清除了,但是父级本身脱离了文档流,会对父级后面的兄弟盒子的布局造成影响。如果设置父级为display:flex,内部的浮动就会失效。所以通常只是用overflow:hidden清除浮动

7.Vuex

7.1是什么

Vuex是集中管理项目公共数据的。

7.2属性的作用

  1. state属性用来存储公共管理的数据
  2. mutations属性定义改变state中数据的方法,注意:不要在mutation的方法中写异步方法ajax,那样数据就不可跟踪了
  3. getters属性可以认为是定义store的计算属性。就像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖发生了改变才会被重新计算
  4. action属性类似于mutation,不同在于:action提交的是mutation,而不是直接变更状态,action可以包含任意异步操作。
  5. module属性是将store分割成模块。每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块。从上至下进行同样方式的分割。

7.3如何使用

state:直接以对象方式添加属性

mutations:通过store.commit调用

action:通过store.dispatch方法触发

getters:直接通过store.getters调用

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

8.js有几种方法判断变量的类型

  1. typeof:常用于判断基本数据类型,对于引用数据类型除了function返回function,其余全部返回object
  2. instanceof:主要用于区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型的检测中null、undefined、symbol检测不出来
  3. constructor:用于检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰
  4. Object.prototype.toString.call():适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据)返回的是该数据类型的字符串

instanceof的实现原理:验证当前类的原型prototype是否会出现在实例的原型链_proto_上,只要在它的原型链上,则结果都为true。因此,instanceof在查找的过程中会遍历左边变量的原型链,直到找到右边变量的prototype,找到返回true,未找到返回false

Object.prototype.toString.call()实现原理:Object.prototype.toString表示一个返回对象类型的字符串,call()方法可以改变this的指向,那么把Object.prototype.toString()指向不同的数据类型上面,返回不同的结果

9.CSS样式优先级规则

第一类是!important,不管引入方式是什么,选择器是什么,它的优先级都是最高的

第二类是引入方式的不同,优先级也会不同,行内样式的优先级是高于内部样式和外部样式的,如果两者使用的选择器是相同的,就看他们在页面中插入的顺序,后面的会覆盖前面的

第三类就是选择器,选择器的优先级是:id选择器 > (类选择器 | 伪类选择器 | 属性选择器) > (后代选择器 | 伪元素选择器) > (子选择器 | 相邻选择器) > 通配符选择器

第四类就是继承样式,是所有样式中优先级比较低的

第五类是浏览器默认的样式优先级是最低的

10.js实现异步的方法

所有的异步任务都是在同步任务执行结束后,从任务队列中依次取出执行,回调函数是异步操作最基本的方法,比如ajax回调,回调函数的优点是简单、容易理解和实现,缺点是不利于代码的阅读和维护,各个部分之间高度耦合,使得程序结构混乱、流程难以追踪(尤其是多个回调函数嵌套的情况),而且每个任务只能指定一个回调函数。此外,它不能使用try catch 捕获错误,不能直接return promise包装了一个异步调用并生成一个promise实例,当异步调用返回的时候根据调用的结果分别调用实例化时传入的resolve和reject方法,then接收到对应的数据,做出相应的处理。promise不仅能够捕获错误,而且也很好地解决了回调地狱的问题,缺点是无法取消promise,错误需要通过回调函数捕获。

Generator函数是ES6提供的一种异步编程解决方案,Generator函数是一个状态机,封装了多个内部状态,可暂停函数,yield可暂停,next方法可启动,每次返回的是yield后的表达式结果。优点是异步语义清晰,缺点是手动迭代Generator函数很麻烦,实现逻辑有点绕。async/awt是基于promise实现的,async/awt使得异步代码看起来像同步代码,所以优点是,使用方法清晰明了,缺点是awt将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使用了awt会导致性能上的降低,代码没有依赖性的话,完全可以使用promise.all的方式。

js异步编程进化史:callback -> promise -> generator/yield -> async/awt

async/awt函数对generator函数的改进,体现在意下三点:

  1. 内置执行器。generator函数的执行必须靠执行器,而async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样,只要一行。
  2. 更广的适用性。yield命令后面只能是Thunk函数或promise对象,而async函数的awt命令后面,可以跟promise对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。
  3. 更好的语义。async和awt,比起星号和yield,语义更清楚了。async表示函数里面有异步操作,awt表示紧跟在后面的表达式需要等待结果。目前使用很广泛的就是promise和async/awt。

11.Vue2.0双向绑定原理与缺陷

Vue响应式指的是:组件的data发生变化,立刻触发试图的更新

原理:Vue采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据变动时发布消息给订阅者,订阅者收到消息后进行相应的处理。通过原生js提供的监听数据的API,当数据发生变化的时候,在回调函数中修改dom。

核心API:Object.defineProperty

Object.defineProperty API的使用:

作用:用来定义对象属性

特点:默认情况下定义的数据属性不能修改。描述属性和存取属性不能同时使用,使用会报错。

响应式原理:获取属性值会触发getter方法,设置属性值会触发setter方法,在setter方法中调用修改dom的方法。

Object.defineProperty缺点:

  1. 一次性递归开销很大,如果数据很大,大量的递归会导致调用栈溢出
  2. 不能监听对象的新增属性和删除属性
  3. 无法正确的监听数组的方法,当监听的下标对应的数据发生改变时。

12.数组去重的方法

  1. 利用对象属性key排除重复项:遍历数组,每次判断对象中是否存在该属性,不存在就存储在新数组中,并且把数组元素作为key,设置一个值,存储在对象中,最后返回新数组。这个方法的优点是效率较高,缺点是占用了较多空间,使用的额外空间有一个查询对象和一个新数组。
  2. 利用set类型数据无重复项:new一个set,参数为需要去重的数组,set会自动删除重复的元素,再将set转为数组返回。这个方法的优点是效率更高,代码简单,思路清晰,缺点是可能会有兼容性问题。
  3. 从头遍历数组,如果元素在前面出现过,则将当前元素挪到最后面,继续遍历,直到遍历完所有元素,之后将那些被挪到后面的元素抛弃。这个方法因为是直接操作数组,占用内存较少
  4. filter + indexof去重:这个方法和第一种方法类似,利用Array自带的filter方法,返回arr.indecOf(num)等于index的num。原理就是indexOf会返回最先找到的数字的索引,假设数组是[1, 1],在对第二个1使用indexOf方法时,返回的是第一个1的索引0.这个方法的优点是可以在去重的时候插入对元素的操作,可拓展性强
  5. reduce + includes去重:这个方法就是利用reduce遍历和传入一个空数组作为去重后的新数组,然后内部判断新数组中是否存在当前遍历的元素,不存在就插入到新数组中。这种方法时间消耗多,内存空间也有额外占用

以上5个方法中,在数据低于10000条的时候没有明显的差别,高于10000条,第一种和第二种的时间消耗最少,后面三种时间消耗依次增加,由于第一种内存空间消耗比较多,且现在很多项目不再考虑低版本浏览器的兼容性问题,所以建议使用第二种去重方法,简洁方便

13.null和undefined的区别,如何让一个属性变为null

undefined就是当一个变量没有被赋值或者是一个函数没有返回值又或者是某个对象不存在某个属性却去访问或者函数定义了形参但没有传递实参,这些都是undefined;null代表的是对象的值未设置,相当于一个对象没有设置指针地址就是null。undefined表示一个变量初始状态值,而null则表示一个变量被人为的设置为空对象,而不是原始状态。

让一个变量变为null,直接给该变量赋值为null就可以了。

加分:

null其实属于自己的类型Null,而不属于Object类型,typeof之所以会判定为Object类型,是因为JavaScript数据类型再底层都是以二进制的形式表示的,二进制的前三位都是0会被typeof判断为Object类型,而null的二进制位恰好都是0,因此,null被误判为Object类型。

14.CSS的浮动

浮动的作用:

  1. 设置浮动的图片可以实现文字环绕图片的效果
  2. 设置了浮动的块级元素,可以排列在同一行
  3. 设置了浮动的行内元素可以设置宽高,同时也可以按照浮动设置的方向对齐排列盒子

设置浮动元素的特点:

  1. 设置了浮动,该元素会脱标,也就是不再占有原来的位置

清除浮动的方法:

  1. after伪元素清除浮动
.clearfix::after {
    content: '';
    display: table;
    clear: both; //兼容IE低版本
}
.clearfix {
    *zoom: 1;
}
  1. overflow:hidden
  2. 额外标签法

15.es6箭头函数

箭头函数就是相当于匿名函数,简化了函数定义。

如果参数值只有一个可以省略()小括号,函数体只有一条语句的时候,可以省略{ }大括号和return;如果有多个参数或者函数体有多条语句是不能省略小括号、大括号、还有return的。

箭头函数的特点:

最大的特点就是没有this指向,所以它的this是从外部获取,也就是继承外部的执行上下文中的this;箭头函数也不能作为构造函数,同时通过call()和apply()方法调用一个函数的时候,只能传递参数,不能绑定this,第一个参数会被忽略;箭头函数也没有原型和super。不能使用yield关键字,所以箭头函数不能用作Generator函数。不能返回直接对象字面量。

应用场景:

  1. 简单的函数表达式,内部没有this引用,没有递归、事件绑定、解绑定,适用于map、filter等方法中
  2. 内层函数表达式,需要调用this,且this应与外层函数一致时

16.call、apply、bind的作用和区别

作用:call、apply、bind的作用都是用来改变函数运行时的this指向。

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

call的应用场景:对象的继承

bind的应用场景:在Vue或React框架中,使用bind将定义的方法中的this指向当前类

17、this指向(普通函数、箭头函数)

this关键字由来:在对象内部的方法中使用对象内部的属性是一个非常普遍的需求。但是JavaScript的作用域机制并不支持这一点,基于这个需求,JavaScript又搞出来另一套this机制。

this存在的场景有三种:全局执行上下文和函数执行上下文的eval执行上下文。在全局执行环境中无论是否在严格模式下,(在任何函数体外部)this都指向全局对象。在函数执行上下文中访问this,函数的调用方式决定了this的值。在全局环境中调用一个函数,函数内部的this指向的是全局对象window,通过一个对象来调用其内部的一个方法,该方法的执行上下文中的this指向对象本身。

普通函数this指向:当函数被调用的时候,this指向全局对象window;通过一个对象来调用其内部的一个方法,该方法的执行上下文中的this指向该对象本身;构造器调用,this指向返回的这个对象。

箭头函数this指向:箭头函数本身是没有this的,它并不会创建其自身的执行上下文,所以箭头函数的this取决于它的外部函数。

18.CSS尺寸设置的单位

px:pixel像素的缩写,绝对长度单位,它的大小取决于屏幕的分辨率,是开发网页中常见的使用单位

em:相对长度单位,在font-size中使用时相对于父元素的字体大小,在其他属性中使用是相对于自身的字体大小,如width。如果当前元素的字体尺寸未设置,由于字体大小可继承的原因,可逐级向上查找,最终找不到则相对于浏览器默认字体大小

rem:相对长度单位,相对于根元素的字体大小,根元素字体大小未设置,使用浏览器默认字体大小

vw:相对长度单位,相对于可视窗口宽度的1%

vh:相对长度单位,相对于可视窗口高度的1%

rem应用:在移动端网页开发中,页面要做成响应式的,可使用rem配合媒体查询或者flexible.js实现。原理是通过媒体查询或者flexible.js,能够在屏幕尺寸发生改变时,重置html根元素的字体大小,页面中的元素都是使用rem为单位设置的尺寸,因此只要改变根元素字体大小,页面中的其他元素的尺寸就自动跟着修改

vw应用:由于vw被更多浏览器兼容之后,在做移动端响应式页面时,通常使用vw配合rem。原理是使用vw设置根元素html字体的大小,当窗口大小发生改变,vw代表的尺寸随着修改,无需加入媒体查询个flexible.js,页面中的其他元素仍使用rem为单位,就可实现响应式。

19.元素水平垂直居中的方法

  1.  设置元素相对于父级元素定位position:absolute;top:50%;left:50%;再给该元素设置平移属性transform:translate(-50%, -50%) 。这种方式兼容性好,被广泛使用。
  2. 设置元素的父级为弹性盒子display:flex;设置父级和盒子内部子元素水平垂直都居中justify-content:center;align-items:center。这种方式代码简洁,但是兼容性ie11以上支持
  3. 设置元素的父级为网格元素display:grid;设置父级和盒子内部子元素水平垂直都居中justify-content:center;align-items:center。这种方式代码简洁,但是兼容性ie10以上支持
  4. 设置元素的父级为表格元素displa:table-cell;其内部元素水平垂直都居中text-align:center;vertical-align:middle;设置子元素为行内块display:inline-block

20.js变量提升

变量提升是指js的变量和函数声明会在代码编译期,提升到代码的最前面。当然这个的前提是在使用var进行声明变量的时候,并且变量提升是只对声明进行提升不对赋值提升,同时函数的声明提升会比变量的提升优先。变量提升的结果可以在变量初始化之前访问该变量,返回的是undefined。在函数声明之前可以调用该函数。

21.HashRouter和HistoryRouter的区别和原理

22.map和forEach的区别

首先两者都可以用来遍历数组,但是map有返回值可以开辟一个新的空间,return出来一个length和原数组一致的数组,forEach默认是没有返回值的,返回的结果是undefined,可以通过在函数体内部使用索引修改数组元素

23.事件循环Event loop,宏任务与微任务

浏览器的事件循环:执行js代码的时候,遇见同步任务,直接推入调用栈中执行,遇到异步任务,将该任务挂起,等到异步任务有返回之后推入到任务队列中,当调用栈中的所有同步任务全部执行完毕,再将任务队列中的异步任务依次推入并执行,重复执行这一系列的行为叫作事件循环。

异步任务又分为宏任务与微任务

宏任务:任务队列中的任务称为宏任务,每一个宏任务中都包含了一个微任务队列

微任务:等宏任务中的主要功能都完成之后,渲染引擎不急着去执行下一个宏任务,而是执行当前宏任务中的微任务

宏任务包含:执行script标签内部代码、setTimeout / setInterval、ajax请求等

微任务包括Promise、Object.observe、process.nextTick等

24.Vue3.0实现数据双向绑定的方法

Vue3.0是通过Proxy实现的数据双向绑定,Proxy是ES6中新增的一个特性,实现的过程是在目标对象之前设置了一层“拦截”,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

用法:ES6原生提供Proxy构造函数,用来生成Proxy实例。var proxy = new Proxy(target, hanlder)target:是用Proxy包装的被代理对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。handler:是一个对象,其声明了代理target的一些操作,其属性是当执行一个操作时定义代理行为的函数

Proxy的优点:可以劫持整个对象,并返回一个新对象

25.Diff算法

26.三栏布局的实现方案

三栏布局,要求左右两边的盒子宽度固定,中间盒子宽度自适应,盒子的高度都是随内容撑高的,一般都是中间盒子内容多,为了保证页面渲染快,在写结构的时候,需要把中间盒子放在左右盒子的前面。实现三栏布局的方法通常是圣杯布局和双飞翼布局。

圣杯布局实现方案:三个元素放在同一个父级元素中,代表中间盒子的元素放在最前面,父级盒子设置左右padding,三个盒子全部浮动,设置中间盒子宽度为100%,左右盒子设置固定宽度,设置左边盒子左边距-100%同时相对自身定位,右边平移自身宽度,右边盒子设置右边距-自身宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。

双飞翼布局实现方案:三个盒子对应三个元素,其中中间盒子套了两层,中间盒子内部设置margin,三个盒子全部浮动,设置中间盒子宽度为100%,左右盒子设置固定宽度,最后设置父级盒子清除浮动,否则父级盒子的高度无法被撑开。

27.浏览器垃圾回收机制

浏览器垃圾回收机制根据数据存储方式的不同可以分为栈垃圾回收和堆垃圾回收两种。

栈垃圾回收就是当一个函数执行结束之后,JavaScript引擎会通过向下移动ESP来销毁该函数保存在栈中的执行上下文,遵循先进后出原则。

堆垃圾回收:当函数执行结束,栈空间处理完成了,堆空间的数据虽然没有被引用,但是还是存储在堆空间中,需要垃圾回收器将堆空间中的垃圾数据回收。为了使垃圾回收达到更好的效果,根据对象的生命周期不一样,使用不同的垃圾回收算法。

28.Vue的keep-alive

作用:缓存组件,提升性能,避免重复加载一些不需要经常变动且内容较多的组件。

使用方法:使用标签对需要缓存的组件进行包裹,默认情况下被标签包裹的组件都会进行缓存,区分被包裹的组件是否缓存有两种方法:第一种是给keep-alive添加属性,组件名称指的是具体组件添加的name,不是路由里面的name。include包含的组件(可以为字符串、数组、以及正则表达式,只有匹配的组件会被缓存)。exclude排除的组件(以字符串、数组,以及正则表达式,任何匹配的组件都不会被缓存)。第二种是和路由配合使用:在路由中添加meta属性。使用keep-alive导致组件不重新加载,,也就不会重新执行生命周期的函数,如果要解决这个问题,就需要两个属性进入时触发:activated,退出时触发:deactivated

适用的场景:首页展示固定数据的组件,比如banner九宫格

29.CSRF攻击是什么

CSRF跨站点请求伪造(Cross Site Request Forgery)和XSS攻击一样,有巨大的危害性,就是攻击者盗用了用户端额身份,以用户的身份发送恶意请求,但是对服务器来说这个请求是合理的,这样就完成了攻击者的目标。

CSRF攻击的过程原理是:

用户打开浏览器,访问目标网站A,输入用户名和密码请求登录。

用户信息在通过认证后,网站A产生一个cookie信息返回给浏览器,这个时候用户以可正常发送请求到网站A

用户在没有退出网站A之前在同一个浏览器打开了另一个新网站B

新网站B收到用户请求之后返回一些攻击代码,并发出一个请求要求访问返回cookie的网站A。

浏览器收到这些攻击性代码之后根据新网站B的请求在用户不知道的情况下以用户的权限操作了cookie并向网站A服务器发起了合法的请求。

预防CSRF攻击的策略:

30.XSS攻击是什么

XSS是跨站脚本攻击(Cross Site Scripting),不写成CSS是为了避免和层叠样式表的缩写混淆,所以将跨站脚本攻击写成XSS。攻击者可以通过向Web页面里面插入script代码,达到攻击者的目的。XSS的危害一般是泄露用户的登录信息cookie,攻击者可以通过cookie绕过登录步骤直接进入站点。XSS的分类为反射型和存储型。反射型就是临时通过url访问网站,网站服务端将恶意代码从url中取出,拼接在HTML中返回给浏览器,用户就会执行恶意代码。存储型就是将恶意代码以留言的形式保存在服务器数据库,任何访问网站的人都会受到攻击。

31.js继承的方法和优缺点

原型链继承:让一个构造函数的原型时另一个类型的实例,那么这个构造函数new出来的实例就具有该实例的属性。优点:写法方便简洁,容易理解。缺点:在父类型构造函数中定义的引用类型值的实例属性,会在子类型原型上变成原型属性被所有子类型实例所共享,同时在创建子类型的实例的时候,不能像超类型的构造函数中传递参数。

借用构造函数继承:在子类型构造函数的内部调用父类型构造函数;使用apply()或call()方法将父对象的构造函数绑定在子对象上。优点:解决了原型链实现继承的不能传参的问题和父类的原型共享的问题。缺点:方法都在构造函数中定义,因此无法实现函数的复用。在父类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数的模式。

组合继承:将原型链和借用构造函数的组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能保证每个实例都有自己的属性。优点:解决了原型链继承和借用构造函数继承造成的影响。缺点:无论在什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

原型式继承:在一个函数A内部创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。本质上,函数A时对传入的对象执行了一次浅复制。ECMAScript 5通过增加Object.create()方法将原型式继承的概念规范化了。这个方法接收两个参数:作为新对象原型的对象,以及给新对象定义额外属性的对象(第二个可选)。在只有一个参数时,Object.create()与这里的函数A方法效果相同。优点:不需要单独创建构造函数。缺点:属性中包含的引用值始终会在相关对象间共享。

寄生式继承:类似于寄生构造函数和工厂模式;创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象。优点:写法简单,不需要单独创建构造函数。缺点:通过寄生式继承给对象添加的函数会导致函数难以重用。

寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型。优点:高效率只调用一次父构造函数,并且因此避免了在子原型上面创建不必要多余的属性,与此同时,原型链还能保持不变。缺点:代码复杂

32.defer和async的区别

“浏览器会立即加载js文件并执行指定的脚本,“立即指的是在渲染该script标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行”加上async属性,加载js文档和渲染文档可以同时进行(异步),当js加载完成,js代码立即执行,会阻塞HTML渲染。加上defer,加载后续文档元素的过程将和script.js的加载并行进行(异步),当HTML渲染完成,才会执行js代码。”

渲染阻塞的原因:由于js是可操作DOM的,如果再修改这些元素属性同时渲染页面,那么渲染线程前后获得的元素数据就可能不一致了。因此为了防止渲染出现不可预期的结果,浏览器设置GUI渲染线程与js引擎为互斥的关系。当浏览器在执行js程序的时候,GUI渲染线程会被保存在一个队列中,直到js程序执行完成才会接着执行。如果js执行时间过长,这样就会造成页面的渲染不连贯。

33.浏览器如何渲染页面的

浏览器拿到HTML,先将HTML转换成dom树,再将CSS样式转换成stylesheet,根据dom树和stylesheet创建布局树,对布局树进行分层,为每个图层生成绘制列表,再将图层分成图块,紧接着光栅化将图块转换成位图,最后合成绘制生成页面。

分层的目的:避免整个页面渲染,把页面分成多个图层,尤其是动画的时候,把动画独立出一个图层,渲染时只渲染该图层,transform、z-index等,浏览器会自动优化生成图层

光栅化目的:页面如果很长,但是可视化区域很小,避免渲染非可视区的样式造成资源浪费,所以将每个图层又划分成多个小个子,当前值渲染可视区附近区域。

34.computed和watch的区别和运用场景

computed:是计算属性,依赖其它属性值,并且computed的值有缓存,只有依赖的属性值发生改变,下一次获取computed的值时才会重新计算computed的值。必须返回结果、必须调用、不能异步监听。

watch:更多的是观察作用,支持异步,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作

computed应用场景:需要进行数值计算,并且依赖于其它数据时,应该使用computed,因为可以利用computed的特性,避免每次获取值时都要重新计算

watch应用场景:需要在数据变化时执行异步或开销较大的操作时,使用watch选项允许我们执行异步操作(访问一个API),限制我们执行该操作的频率。

35.Vue中$nextTick的作用与原理

Vue在更新DOM时是异步执行的,在修改数据后,视图不会立即更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。所以修改完数据,立即在方法中获取DOM,获取的仍然是未修改的DOM。

$nextTick的作用:可以让我们在下次dom更新循环结束之后执行延迟回调,用于获得更新后的dom。

$nextTick的原理:$nextTick本质是返回一个Promise

应用场景:在钩子函数created()里面想要获取操作DOM,把操作DOM的方法放在$nextTick中。

36.new一下会发生什么

new关键字会进行如下操作:

  1. 创建一个空对象{ }
  2. 为新创建的对象添加属性_proto_,将该属性链接至构造函数的原型对象
  3. 将新创建的对象作为this的上下文
  4. 如果该函数没有返回对象,则返回this。

new关键字后面的构造函数不能时箭头函数。

37.token能放在cookie中吗

能。token一般是用来判断用户是否登录的,它内部包含的信息有:UID(用户唯一的身份标识)、time(当前时间的时间戳)、sign(签名,token的前几位以哈希算法压缩成的一定长度的十六进制字符串)

token可以存放在在cookie中,token是否过期,应该由后端来判断,不由前端判断,所以token存储在cookie中只要不设置cookie的过期时间就可以了,如果token失败,就让后端在接口中返回固定状态表示token失败,需要重新登录,再重新登录的时候,重新设置cookie中的token就行。

token认证流程:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端签发一个token,并把它发送给客户端
  4. 客户端接收token之后会把它存储起来,比如放在cookie里面或者localStorage里面
  5. 客户端每次发送请求时都需要带着服务端签发的token(把token放到HTTP的Header里面)
  6. 服务端收到请求后,需要验证请求例带有的token,如验证成功则返回对应的数据

38.浏览器输入URL发生了什么

输入地址,浏览器查找域名的IP地址,浏览器向该ip地址的web服务器发送了一个HTTP请求,在请求发送之前浏览器和服务器建立TCP的三次握手,判断是否是HTTP缓存,如果是强制缓存且在有效期内,不再向服务器发送请求,如果是HTTP协商缓存向后端发送请求且和后端服务器对比,在有效期内,服务器返回304,直接从浏览器获取数据,如果不在有效期内服务器返回200,返回新数据。请求发送出去服务器返回重定向,浏览器再按照重定向的的地址重新发送请求。如果请求的参数有问题,服务器端返回304,如果服务器端挂了返回500.如果有数据一切正常,当浏览器拿到服务器的数据之后,开始渲染页面同时获取HTML页面中的图片、音频、视频、CSS、js,在这期间获取到js文件之后,会直接执行js代码,阻塞浏览器渲染,因为渲染引擎的js引擎互斥,不能同时工作,所以通常把script标签放在body标签的底部。渲染过程就是先将HTML转换成dom树,在将CSS样式转换成stylesheet,根据dom树和stylesheet创建布局树,对布局树进行分层,为每个图层生成绘制列表,再将图层分成图块,紧接着光栅化将图块转换成位图,最后合成绘制生成页面。

39.Vue组件通信的方式

Vue组件通信的方式分为两大类:一类是父子组件通信,一类是任何关系类型组件通信(父子、兄弟、非兄弟)。

父子组件通信方式:父给子传递数据,通过给子组件添加自定义属性,比如:list是父组件给子组件传递的数据,子获取父的数据,在子组件中使用props属性获取子给父传递数据,通过给子组件传递父组件的方法,子组件调用父组件的方法传递数据,比如:deleteHandler就是父组件的函数,在子组件中通过this.$emit('方法名', 参数),调用父组件的方法,并把数据传递到父组件。props是只读,不可以被修改,所有被修改都会失效和被警告。

任何关系类型组件通信方式:EventBus:使用方法是创建一个新的Vue实例,需要通信的组件都引入该Vue实例,传递数据的组件使用event.$emit('方法名', 参数)发送数据,接收数据的组件使用event.$on('名称',方法)接收数据。

entBus优缺点:

缺点:vue是单页应用,如果你在某一个页面刷新了之后,与之相关的EventBus会被移除,这样就导致业务走不下去,同时如果页面中有反复操作的业务,EventBus在监听的时候就会触发很多次,需要好好处理EventBus在项目中的关系。在vue页面销毁时,同时移除EventBus事件监听。

优点:解决了多层组件之间繁琐的事件传播,使用原理十分简单,代码量少。适合业简单,组件传递数据较少的项目,大型项目业务复杂的还是尽量使用vuex。

40.v-if和v-show的区别

作用:都是控制元素显示和隐藏的指令。

区别:v-show:控制的元素无论是true还是false,都被渲染出来了,通过display:none控制元素隐藏,v-if:控制的元素是true进行渲染,如果是false不渲染,在dom树结构中不显示。

应用:v-show:适合使用在切换频繁显示/隐藏的元素上。v-if:适合使用在切换不频繁,且元素内容很多,渲染一次性能消耗很大的元素上。

41.什么是MVVM

42.对SPA单页面的理解它的优缺点是什么

43.什么是盒子模型

盒子模型分为两种:标准盒模型和怪异盒模型。标准盒模型是由宽高内外边距边框还有盒子的内容来决定盒子大小的;怪异盒模型,所设置的宽度和高度就是盒子的大小,不会因为加了内外边距而撑开盒子。设置标准盒模型:box-sizing:content-box,设置怪异盒模型:box-sizing:border-box

44.怎样理解Vue的单项数据流

45.Vue的父组件和子组件生命周期

46.钩子函数执行顺序

47.在哪些生命周期内调用异步请求

48.第一次页面加载会触发哪几个钩子

49.vue-router路由模式有几种

50.vue-router有哪几种导航钩子

51.怎么定义vue-router的动态路由?怎么获取传过来的值?

52.CSS的定位

53.原型和原型链

原型:就是在js中每定义一个对象,对象里面都会包含一些预设的属性,所有的函数对象都有一个prototype属性,这个属性指向一个对象,该对象称为函数的原型对象。原型对象默认有一个constructor属性,值为对应的构造函数。

原型链:通过对象_proto_属性指向函数的原型对象,一层一层往上找,直到找到Object的原型对象(Object.prototype)为止,这个层层继承的链接结构叫作原型链。

54.防抖和节流要怎么实现

55.HTML5语义化如何理解,有什么好处

HTML语义化就是指在使用HTML标签构建页面的时候,为了避免大篇幅的使用无语义化的标签,比如

等标签,我们可以使用更具有语义化的标签,比如

你可能感兴趣的:(Web面试题,前端,服务器,java)