前端面试汇总
1. 浏览器中,从输入url到页面显示出来,具体的流程是什么?
1.DNS解析
2.TCP连接
3.发送HTTP请求
4.服务器处理请求并返回需要的数据
5.浏览器解析渲染页面
解析HTML,生成DOM树,解析CSS,生成CSSOM树
将DOM树和CSSOM树结合,生成渲染树(Render Tree)
Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
Display:将像素发送给GPU,展示在页面上
6.连接结束
2. http状态码的了解
1xx(临时响应)
表示临时响应并需要请求者继续执行操作的状态代码
2xx (成功)
表示成功处理了请求的状态码。
常见的2开头的状态码有:200 – 服务器成功返回网页
3xx (重定向)
表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向
常见的3字开头的状态码有:
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
4xx(请求错误) 这些状态代码表示请求可能出错,妨碍了服务器的处理。
常见的4字开头的状态有:404 – 请求的网页不存在
5xx(服务器错误)
这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。
常见的以5开头的状态码有:
500 (服务器内部错误) 服务器遇到错误,无法完成请求。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
3. http2.0的优点?
解析速度快
服务器解析 HTTP1.1 的请求时,必须不断地读入字节,直到遇到分隔符 CRLF 为止。而解析 HTTP2 的请求就不用这么麻烦,因为 HTTP2 是基于帧的协议,每个帧都有表示帧长度的字段。
多路复用
HTTP1.1 如果要同时发起多个请求,就得建立多个 TCP 连接,因为一个 TCP 连接同时只能处理一个 HTTP1.1 的请求。
在 HTTP2 上,多个请求可以共用一个 TCP 连接,这称为多路复用。同一个请求和响应用一个流来表示,并有唯一的流 ID 来标识。 多个请求和响应在 TCP 连接中可以乱序发送,到达目的地后再通过流 ID 重新组建。
首部压缩
HTTP2 提供了首部压缩功能。多请求请求时,有很多消息头都是重复的。如果可以把相同的首部存储起来,仅发送它们之间不同的部分,就可以节省不少的流量,加快请求的时间。
HTTP/2 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送。如果服务器收到了请求,它会照样创建一张表。 当客户端发送下一个请求的时候,如果首部相同,它可以直接发送这样的首部块:服务器会查找先前建立的表格,并把这些数字还原成索引对应的完整首部。
优先级
HTTP2 可以对比较紧急的请求设置一个较高的优先级,服务器在收到这样的请求后,可以优先处理。
流量控制
由于一个 TCP 连接流量带宽(根据客户端到服务器的网络带宽而定)是固定的,当有多个请求并发时,一个请求占的流量多,另一个请求占的流量就会少。流量控制可以对不同的流的流量进行精确控制。
服务器推送
HTTP2 新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。换句话说,除了对最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确地请求。
4. cookie,localStorage和sessionStorage的区别
cookie可以设置失效时间,但没有自己的存取取的方法,需要时封装,每次请求时跟随请求发送,而localStorage和sessionStorage可以有自己存取的方法例如:setItem(),getItem(),removeItem(),clear() 如:localStorage.setItem(‘属性’,值)
5. 设计模式知道那些?具体用法
单例模式:就是保证一个类只有一个实例,实现的方法一般是先判断实例存在与否,如果存在直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。在JavaScript里,单例作为一个命名空间提供者,从全局命名空间里提供一个唯一的访问点来访问该对象。
观察者模式: 观察者的使用场合就是:当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式。
工厂模式解决了重复实例化的问题,缺点,创建不同对象其中属性和方法都会重复建立,消耗内存;还有函数识别问题等等。
6. 怎么处理web安全
可能的原因:
权限控制
SQL注入
URL安全测试
XSS(跨站脚本攻击)
CSRF(跨站请求伪造)
URL跳转漏洞
其他安全方面的考量
解决:1、永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式或限制长度;对单引号和双"-"进行转换等。
2、永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。
3、永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4、不要把机密信息直接存放,加密或者Hash掉密码和敏感的信息。
5、应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装。
6、SQL注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用SQL注入检测工具jsky、MDCSOFT SCAN等。采用MDCSOFT - IPS可以有效的防御SQL注入、XSS攻击等。
使用https、HTTPS与HTTP虽然只差一个SSL,但是通信安全得到了大大的保障,通信的四大特性都以解决,解决方式如下:
机密性:混合算法
完整性:摘要算法
身份认证:数字签名
不可否定:数字签名
同时引入第三方证书机构,确保公开秘钥的安全性
7. Seo是什么?怎么优化?
SEO(Search Engine Optimization):汉译为搜索引擎优化。是一种方式:利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。目的是让其在行业内占据领先地位,获得品牌收益。很大程度上是网站经营者的一种商业行为,将自己或自己公司的排名前移。
优化:
SSR服务器渲染
静态化
预渲染prerender-spa-plugin
使用Phantomjs针对爬虫做处理
合理的title、description、keywords
语义化的HTML代码,符合W3C规范
非装饰性图片必须加alt
友情链接
外链
向各大搜索引擎提交收录自己的站点
重要的内容放在前面
少用iframe:iframe中的内容是不会被抓取到的
提高网站速度:这也是搜索引擎排序的一个重要指标
流量:访问你的网站的人越多,排名也会越靠前.
8. 原生ajax的交互过程(即流程
先创建XHR对象即XMLHttpRequest()
然后open准备发送,open中有三个参数一是提交方式get和post,二是接口地址,三是同步和异步
第三步是用send发送
第四步再发送的过程中通过onreadystatechange来监听接收的回调函数,可以通过判断readyState==4和status==200来判断是否成功返回,然后通过responseText接收成功返回的数据
9. 数组常用方法、用法是什么?
push,pop,unshift,shift,splice,join,concat,forEach,filter,map,sort,some,every
10. 数组排序
11. 数组去重
第一种:利用ES6的set来实现 例如:[...new Set(arr)]
第二种:借用临时对象的方式
12. JS事件代理(也称事件委托)是什么,及实现原理
JS事件代理就是通过给父级元素(例如:ul)绑定事件,不给子级元素(例如:li)绑定事件,然后当点击子级元素时,通过事件冒泡机制在其绑定的父元素上触发事件处理函数,主要目的是为了提升性能,因为我不用给每个子级元素绑定事件,只给父级元素绑定一次就好了,在原生js里面是通过event对象的targe属性实现
var ul = document.querySelector("ul");
ul.onclick = function(e){//e指event,事件对象
var target = e.target || e.srcElement; //target获取触发事件的目标(li)
if(target.nodeName.toLowerCase() == 'li'){//目标(li)节点名转小写字母,不转的话是大写字母
alert(target.innerHTML)
}
}
jq方式实现相对而言简单 $(“ul”).on(“click”,“li”,function(){//事件逻辑}) 其中第二个参数指的是触发事件的具体目标,特别是给动态添加的元素绑定事件,这个特别起作用
13. 构造函数、原型、原型链、JS面试对象的理解
构造函数模式的目的就是为了创建一个自定义类,并且创建这个类的实例。构造函数模式中拥有了类和实例的概念,并且实例和实例之间是相互独立的,即实例识别。
构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。另外就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。
在JavaScript中,每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。
让构造函数和实例原型之间的关系:
构造函数 + prototype = 实例原型
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
在JavaScript中万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条,专业术语称之为原型链。
当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。如果没有则去原型的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined。
Object是JS中所有对象数据类型的基类(最顶层的类)在Object.prototype上没有__proto__这个属性。
面试对象:将所需要做的功能抽象成一个“对象”,然后反复调用这个对象来完成你想要的功能
14. 深拷贝、浅拷贝的区别,并实现深拷贝
对象浅拷贝可以理解为改变一个对象属性值,另一个对象属性也会发生改变,即互相影响,
对象深拷贝即就是说改变一个对象属性,另一个对象属性值不会发生改变,可以通过多种方法来实现对象深拷贝,
深拷贝方法:
第一种方法:通过JSON.stringify和JSON.parse来实现
var obj={name:’1610A’}
var obj2=JSON.parse(JSON.stringify(obj))
第二种方法:通过递归来实现
15. JS原生事件如何绑定
JS原生绑定事件主要为三种:
一是html事件处理程序
例如:<button onclick=”事件处理函数”>点我</button>
二是DOM0级事件处理程序
例如:var btn=document.getElementById(‘id元素’)
btn.onclick=function() {
//要处理的事件逻辑
}
三是DOM2级事件处理程序
例如: var btn=document.getElementById(‘id元素’)
//绑定事件
btn.addEventListener(‘click’,绑定的事件处理函数名,false)
//移除事件
btn.removeEventListener(‘click’,要移除的事件处理函数名,false)
16. ==与===的区别
== 用于比较两者是否相等,忽略数据类型。
=== 用于更严谨的比较,值和值的数据类型都需要同时比较。
17. BFC相关?(div塌陷问题或者clearfix(清除浮动))
定位方式:普通流 (normal flow)、浮动 (float)、绝对定位 (absolute positioning)
BFC 即 Block Formatting Contexts (块级格式化上下文):具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。
要元素满足下面任一条件即可触发 BFC 特性:
body 根元素
浮动元素:float 除 none 以外的值
绝对定位元素:position (absolute、fixed)
display 为 inline-block、table-cells、flex
overflow 除了 visible 以外的值 (hidden、auto、scroll)
BFC特性:
同一个 BFC 下外边距会发生折叠
BFC 可以包含浮动的元素(清除浮动)
BFC 可以阻止元素被浮动元素覆盖
清除浮动解决的方法有很多,主要目的是让父级元素有高度
方法一:给父级元素设置绝对定位:position:absolute
方法二:给父级元素设置overflow:hidden;
方法三:通过伪对象来实现
.clearfix:after {
content: " ";
display: block;
clear: both;
height: 0;
}
18. 对盒模型的理解
盒模型其实就是浏览器把一个个标签都看一个形象中的盒子,那每个盒子(即标签)都会有内容(width,height),边框(border),以及内容和边框中间的缝隙(即内间距padding),还有盒子与盒子之间的外间距(即margin)
用图表示为:
当然盒模型包括两种:IE盒模型和w3c标准盒模型
IE盒模型总宽度即就是width宽度=border+padding+内容宽度
标准盒模型总宽度=border+padding+width
那如何在IE盒模型宽度和标准盒模型总宽度之间切换呢,可以通过box-sizing:border-box或设置成content-box来切换
其中:box-sizing:border-box //IE盒模型
box-sizing:content-box //w3c盒模型、
19. rem和em的区别?百分比与vw、vh的区别?
rem和em都是相对单位,主要参考的标签不同:
rem是相对于根字号,即相对于<html>标签的font-size实现的,浏览器默认字号是font-size:16px
em:是相对于父元素标签的字号,和百分比%类似,%也是相对于父级的,只不过是%相对于父级宽度的,而em相对于父级字号的
百分比是相对于父元素标签的宽度和高度
vw和vh分别相对于屏幕宽度和屏幕高度的,1vw相当于屏幕宽度的1%,100vw相当于满屏宽度100%,
vh和vh类似,只不过是相对于屏幕高度的,1vh相当于屏幕高度的1%,100vh相当于满屏高度的100%,
20. 块元素和行内元素的区别
·块级元素
总是从新的一行开始,即各个块级元素独占一行,默认垂直向下排列;
高度、宽度、margin及padding都是可控的,设置有效,有边距效果;
宽度没有设置时,默认为100%;
块级元素中可以包含块级元素和行内元素。
·行内元素
和其他元素都在一行,即行内元素和其他行内元素都会在一条水平线上排列;
高度、宽度是不可控的,设置无效,由内容决定。
根据标签语义化的理念,行内元素最好只包含行内元素,不包含块级元素。
21. 居中的方法有哪些?flex居中?
其实实现水平垂直剧中方法有很多:
定位:
第一种思路:通过给div设置绝对定位,并且left,right,top,bottom设置为0,margin:auto即可以水平垂直居中
通过给div设置绝对定位,left为50%,top为50%,再给div设置距左是自身的一半即:margin-left:自身宽度/2,margin-top:自身高度/2。
通过给div设置绝对定位,left为50%,top为50%,再给div设置跨左和跟上是自身的一半:transform:translate3d(-50%,-50%,0)
flex布局: display: flex; justify-content: center; align-items: center;
absolute + 负margin
absolute + margin auto
absolute + calc
absolute + transform
lineheight
writing-mode
table
css-table
grid
22. 重绘与回流
在HTML中,每个元素都可以理解成一个盒子,在浏览器解析过程中,会涉及到回流与重绘:
回流:布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
重绘:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制
23. 怎么实现响应式布局
页面元素宽度不用px作为单位,而是尽量使用百分比。
页面框架之间使用流式布局,也就是用float属性,这样当元素超出屏幕宽度的时候会滑倒下面而不是撑出水平滚动条。
注意图片的大小,尤其是宽度,同样尽量使用百分比
使用CSS3中的Media Query(媒体查询)针对不同宽度的设备设置不同的布局和样式,从而适配不同的设备。
24. 防抖与节流
防抖和节流都是为了解决短时间内大量触发某函数而导致的性能问题,比如触发频率过高导致的响应速度跟不上触发频率,出现延迟,假死或卡顿的现象
防抖:在事件被触发n秒后再执行回调函数,如果在这n秒内又被触发,则重新计时。
节流:规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。
防抖和节流的区别:
-- 效果:
函数防抖是某一段时间内只执行一次;而函数节流是间隔时间执行,不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数。
-- 原理:
防抖是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,都会清除当前的 timer 然后重新设置超时调用,即重新计时。这样一来,只有最后一次操作能被触发。
节流是通过判断是否到达一定时间来触发函数,若没到规定时间则使用计时器延后,而下一次事件则会重新设定计时器。
25. 什么是闭包?闭包的作用以及会导致什么问题
闭包说的通俗一点就是打通了一条在函数外部访问函数内部作用域的通道。正常情况下函数外部是访问不到函数内部作用域变量的,
表象判断是不是闭包:函数嵌套函数,内部函数被return 内部函数调用外层函数的局部变量
优点:可以隔离作用域,不造成全局污染
缺点:由于闭包长期驻留内存,则长期这样会导致内存泄露
如何解决内存泄露:将暴露全外部的闭包变量置为null
适用场景:封装组件,for循环和定时器结合使用,for循环和dom事件结合.可以在性能优化的过程中,节流防抖函数的使用,导航栏获取下标的使用
26. 什么是跨域,怎么解决?
基于ajax同源策略,因为安全的考虑,ajax不允许访问不同域名下的资源
只存在前后端访问,后端访问后端不存在跨域问题。
产生跨域的情况有:不同协议,不同域名,不同端口以及域名和ip地址的访问都会产生跨域。
解决:
一、是jsonp
jsonp实现原理:主要是利用动态创建script标签请求后端接口地址,然后传递callback参数,后端接收callback,后端经过数据处理,返回callback函数调用的形式,callback中的参数就是json
二、 是代理(前端代理和后端代理)
前端代理我在vue中主要是通过vue脚手架中的config中的index文件来配置的,其中有个proxyTable来配置跨域的
三、是CORS
CORS全称叫跨域资源共享,主要是后台工程师设置后端代码来达到前端跨域请求的
27. vuex的模块、流程、异步时action?vuex数据持久化?
vuex是一个状态管理工具,主要解决大中型复杂项目的数据共享问题,主要包括state,actions,mutations,getters和modules 5个要素,
主要流程:组件通过dispatch到 actions,actions是异步操作,再actions中通过commit到mutations,mutations再通过逻辑操作改变state,从而同步到组件,更新其数据状态
getters相当于组件的计算属性对,组件中获取到的数据做提前处理的.再说到辅助函数的作用.
因为vuex中的state是存储在内存中的,一刷新就没了,例如登录状态,常见解决方案有:
第一种:利用H5的本地存储(localStorage,sessionStorage)
第二种:利用第三方封装好的插件,例如:vuex-persistedstate
第三种:使用vue-cookie插件来做存储
28. 同步和异步的理解?异步解决方案?回调地狱? Promise?async/await?自己实现promise?
同步即sync,形象的说就是代码一行行执行,前面代码和请求没有执行完,后面的代码和请求就不会被执行
异步:即async,形象的说就是代码可以在当前程序没有执行完,也可以执行后面的代码
异步解决方案主要有:
l 回调函数
l promise
l generator
l async和await
回调地狱:为了实现某些逻辑经常会写出层层嵌套的回调函数,如果嵌套过多,会极大影响代码可读性和逻辑,这种情况也被成为回调地狱
promise的状态改变一次以后就不会再改变,链式调用:then返回的是一个Promise对象,所以能进行链式调用。
async/await其实是Promise的语法糖, async 会将其后的函数(函数表达式或 Lambda)的返回值封装成一个 Promise 对象,而 await 会等待这个 Promise 完成,并将其 resolve 的结果返回出来。
async function doIt() {
console.time('doIt');
let time1 = 300;
let time2 = await step1(time1);//将Promise对象resolve(n+200)的值赋给time2
let time3 = await step1(time2);
let result = await step1(time3);
console.log(`result is ${result}`);
console.timeEnd('doIt');
}
29. 性能优化?
方面:
加载优化
渲染优化
内存优化
电源优化
核心:减少前端资源数量,减小前端资源大小,减少dom操作
代码层面:注意事件的销毁、路由懒加载、提取公共代码、css放前面、组件懒加载、减少代码体积大小、字体图标代替图片、使用事件委托、使用查找表、不覆盖原生方法、减低css选择器复杂度、使用flex、使用 transform 和 opacity实现动画
交互优化:减少请求数量、使用 HTTP2(头部压缩、链路复用、解析快、可设置优先级、流量控制、服务器推送)、减少重绘重排(innerHTML代替DOM操作、避免使用动态属性、脱离文档流操作再合并)
加载优化:按需引入、使用CDN、使用服务端渲染、善用缓存、避免卡顿
打包优化:使用gzip、Webpack 对图片进行压缩、webpack 按需加载代码、提取第三库代码、webpack物理打包以及配置项打包优化
其他优化:图片优化(压缩、懒加载、用webp格式,延迟加载、响应式图片)、使用工作线程Web Workers、少用全局变量
我写过一篇文档:https://www.cnblogs.com/clwydjgs/p/14741264.html
30. es6新特性
ES6新增特性常用的主要有:let/const,箭头函数,模板字符串,解构赋值,模块的导入(import)和导出(export default/export),Promise,还有一些数组字符串的新方法,其实有很多,我平时常用的就这些
31. 说一下call,apply,bind区别
call,apply,bind主要作用都是改变this指向的,但使用上略有区别,说一下区别:
call和apply的主要区别是在传递参数上不同,call后面传递的参数是以逗号的形式分开的,apply传递的参数是数组形式、Apply是以A开头的,所以应该是跟Array(数组)形式的参数]
bind返回的是一个函数形式,如果要执行,则后面要再加一个小括号 例如:bind(obj,参数1,参数2,)(),bind只能以逗号分隔形式,不能是数组形式
32. var let const
var的问题:存在变量提升,后面声明的变量会覆盖前面的变量声明、作用域不可控。
33. 单项数据流、双向数据流
Vue是单项数据流,数据双向绑定
单向数据流主要是vue 组件间传递数据是单向的,即数据总是由父组件传递给子组件,子组件在其内部维护自己的数据,但它无权修改父组件传递给它的数据,当开发者尝试这样做的时候,vue 将会报错。
34. SPA和MPA?
单页应用SPA是一种网络应用程序或网站的模型,它通过动态重写当前页面来与用户交互,这种方法避免了页面之间切换打断用户体验在单页应用中,所有必要的代码(HTML、JavaScript和CSS)都通过单个页面的加载而检索
多页应用MPA(MultiPage-page application),翻译过来就是多页应用在MPA中,每个页面都是一个主页面,都是独立的当我们在访问另一个页面的时候,都需要重新加载html、css、js文件
我们熟知的JS框架如react,vue,angular,ember都属于SPA
单页应用与多页应用的区别
|
单页面应用(SPA) |
多页面应用(MPA) |
组成 |
一个主页面和多个页面片段 |
多个主页面 |
刷新方式 |
局部刷新 |
整页刷新 |
url模式 |
哈希模式 |
历史模式 |
SEO搜索引擎优化 |
难实现,可使用SSR方式改善 |
容易实现 |
数据传递 |
容易 |
通过url、cookie、localStorage等传递 |
页面切换 |
速度快,用户体验良好 |
切换加载资源,速度慢,用户体验差 |
维护成本 |
相对容易 |
相对复杂 |
单页应用优缺点
优点:
具有桌面应用的即时性、网站的可移植性和可访问性
用户体验好、快,内容的改变不需要重新加载整个页面
良好的前后端分离,分工更明确
缺点:
不利于搜索引擎的抓取
首次渲染速度相对较慢
35. mvc与mvvm
MVVM 由 Model,View,ViewModel 三部分构成,Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View 代表UI 组件,它负责将数据模型转化成UI 展现出来,ViewModel 是一个同步View 和 Model的对象。
在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上。
ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
36. vue中,data为什么是函数?
作用域问题,为了保证互不干扰,因为一个组件是可以共享的,但他们的data是私有的,所以每个组件都要return一个新的data对象,返回一个唯一的对象,不要和其他组件共用一个对象。而且data也是一个闭包的经典使用常见。
37. this关键字
this指向直接调用者,而非间接调用者
普通函数中的this:
在Vue所有的生命周期钩子方法(如created,mounted, updated以及destroyed)里 使用this,this指向调用它的Vue实例,即(new Vue)。
箭头函数中的this
箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象, 定义它的时候,可能环境是window; 箭头函数可以方便地让我们在 setTimeout ,setInterval中方便的使用this
38. Vue生命周期
vue生命周期即为一个组件从出生到死亡的一个完整周期,主要包括以下4个阶段:创建,挂载,更新,销毁
创建前:beforeCreate, 创建后:created(有data,无$el)
挂载前:beforeMount, 挂载后:mounted(有data,有$el)
更新前:beforeUpdate, 更新后:updated
销毁前:beforeDestroy, 销毁后:destroyed
新增了使用内置组件 keep-alive 来缓存实例,而不是频繁创建和销毁(开销大)
actived 实例激活(该钩子在服务器端渲染期间不被调用。)
deactived 实例失效 (该钩子在服务器端渲染期间不被调用。)
39. Vue-router路由?路由守卫?懒加载?replace和push的区别?
前端路由实现原理主要通过以下两种技术实现的
第一种:利用H5的history API实现
主要通过history.pushState 和 history.replaceState来实现,不同之处在于,pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录[发布项目时,需要配置下apache]
第二种:利用url的hash实现
我们经常在 url 中看到 #,这个 # 有两种情况,一个是我们所谓的锚点,路由里的 # 不叫锚点,我们称之为 hash,我们说的就是hash,主要利用监听哈希值的变化来触发事件 —— hashchange 事件来做页面局部更新
第三种:abstract模式
适用于所有JavaScript环境,例如服务器端使用Node.js。如果没有浏览器API,路由器将自动被强制进入此模式。
总结:hash 方案兼容性好,而H5的history主要针对高级浏览器。
路由守卫:
第一种:全局路由钩子 beforeEach(to,from,next) { }
第二种:路由独享的钩子
beforeEnter(to,from,next) {
}
第三种:组件内的钩子
beforeRouteEnter(to,from,next) {
//…
}
beforeRouteUpdate(to,from,next) {
//…
}
beforeRouteLeave(to,from,next) {
//…
}
适用场景:动态设置页面标题,判断用户登录权限等
vue路由懒加载主要解决打包后文件过大的问题,事件触发才加载对应组件中的js
this.$router.replace方法方法,不计入history记录,this.$router. Push计入历史
40. 双向绑定的原理,手写
利用ES5中的Object.defineProperty结合观察者模式实现的,然后利用里面的getter和setter来实现双向数据绑定的、发布订阅模式,数据劫持
首先要对数据进行劫持监听,设置一个监听器Observer,用来监听所有属性。如果属性发上变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理的。接着,我们还需要有一个指令解析器Compile,对每个节点元素进行扫描和解析,将相关指令(如v-model,v-on)对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者Watcher接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。
41. packJson.js详细配置?
42. Vue异步队列?nextTick是什么?适用场景?
异步更新队列:Vue在观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲在同一个事件循环中发生的所以数据改变。在缓冲时会去除重复数据,从而避免不必要的计算和DOM操作。然后,在下一个事件循环tick中,Vue刷新队列并执行实际(已去重的)工作。
因为Vue的异步更新队列,$nextTick是用来知道什么时候DOM更新完成的
vue中的nextTick主要用于处理数据动态变化后,DOM还未及时更新的问题,用nextTick就可以获取数据更新后最新DOM的变化
适用场景:
第一种:有时需要根据数据动态的为页面某些dom元素添加事件,这就要求在dom元素渲染完毕时去设置,但是created与mounted函数执行时一般dom并没有渲染完毕,所以就会出现获取不到,添加不了事件的问题,这回就要用到nextTick处理
第二种:在使用某个第三方插件时 ,希望在vue生成的某些dom动态发生变化时重新应用该插件,也会用到该方法,这时候就需要在 $nextTick 的回调函数中执行重新应用插件的方法,例如:应用滚动插件better-scroll时
第三种:数据改变后获取焦点
43. vue核心是什么? vue和jquey的区别?vue与React
vue最大特点我感觉就是“组件化“和”数据驱动“
组件化就是可以将页面和页面中可复用的元素都看做成组件,写页面的过程,就是写组件,然后页面是由这些组件“拼接“起来的组件树
数据驱动就是让我们只关注数据层,只要数据变化,页面(即视图层)会自动更新,至于如何操作dom,完全交由vue去完成,咱们只关注数据,数据变了,页面自动同步变化了,很方便
jquery主要是玩dom操作的“神器“,强大的选择器,封装了好多好用的dom操作方法和如何获取ajax方法 例如:$.ajax()非常好用
vue:主要用于数据驱动和组件化,很少操作dom,当然vue可能通过ref来选择一个dom或组件
vue与react:
相同点:数据驱动视图、组件化、都使用 Virtual DOM
不同点:核心思想不同、组件写法差异、diff算法不同、响应式原理不同
44. vue3.新特性0,ts?
特性:引入Tree-shaking,多出setup生命周期、响应式API、响应式侦听、Composition API(组合API)、Fragment、Teleport、Suspense等
45. Vue常用的修饰符
v-on 指令常用修饰符:
.stop - 调用 event.stopPropagation(),禁止事件冒泡。
.prevent - 调用 event.preventDefault(),阻止事件默认行为。
.capture - 添加事件侦听器时使用 capture 模式。
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
.left - (2.2.0) 只当点击鼠标左键时触发。
.right - (2.2.0) 只当点击鼠标右键时触发。
.middle - (2.2.0) 只当点击鼠标中键时触发。
.passive - (2.3.0) 以 { passive: true } 模式添加侦听器
注意: 如果是在自己封装的组件或者是使用一些第三方的UI库时,会发现并不起效果,这时就需要用`·.native修饰符了,如:
//使用示例:
<el-input
v-model="inputName"
placeholder="搜索你的文件"
@keyup.enter.native="searchFile(params)"
>
</el-input>
v-bind 指令常用修饰符:
.prop - 被用于绑定 DOM 属性 (property)。(差别在哪里?)
.camel - (2.1.0+) 将 kebab-case 特性名转换为 camelCase. (从 2.1.0 开始支持)
.sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。
v-model 指令常用修饰符:
.lazy - 取代 input 监听 change 事件
.number - 输入字符串转为数字
.trim - 输入首尾空格过滤
46. v-for与v-show的区? v-for与v-if优先级
v-if和v-show都可以显示和隐藏一个元素,但有本质区别
v-if是惰性的,只是值为false就不会加载对应元素,为true才动态加载对应元素
v-show:是无论为true和为false都会加载对应html代码,但为false时用display:none隐藏不在页面显示,但为true时页面上用display:block显示其效果
适用场景:切换频繁的场合用v-show,切换不频繁的场合用v-if
v-for的优先级比v-if更高,这意味着 v-if将分别重复运行于每个 v-for循环中。当你想为仅有的一些项渲染节点时,这种优先级的机制会十分有用
47. 虚拟dom是什么,有什么用
提前使用js的方式表示出dom结构树来.存储在内存里面.同样的循环.只会最终合并执行一次,大大的提高了性能.(这个地方有点儿像js中的createElementFragment文档碎片)
而在对比的过程中.通过diff算法进行比较差异.这个比较在我理解而言就是同层比较.降低了时间复杂度空间复杂度一些什么玩意儿.最终把差异同步到真实dom上去.这就是我理解的虚拟dom
在传统的jq中,操作的都是真实的DOM,.而一个真实dom的渲染过程,要经过渲染引擎构建DOM树.构建样式表.组建成render(渲染)树,的过程,要经过不断的重绘回流才能够展示给用户.
那么在直接js操作dom的过程中,比方说一个循环10次插入dom元素,其实每一次都会经历上面的过程..经历大量的重绘回流.代价特别大.性能低下.所以出现了虚拟dom
48. diff算法
diff 算法是一种通过同层的树节点进行比较的高效算法
其有两个特点:
比较只会在同层级进行, 不会跨层级比较
在diff比较的过程中,循环从两边向中间比较
diff 算法在很多场景下都有应用,在 vue 中,作用于虚拟 dom 渲染成真实 dom 的新旧 VNode 节点比较
原理:当数据发生改变时,set方法会调用Dep.notify通知所有订阅者Watcher,订阅者就会调用patch给真实的DOM打补丁,更新相应的视图
源码位置:src/core/vdom/patch.js
49. 解构赋值
一种 Javascript 表达式。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。
一维:深拷贝
二位:浅拷贝
50. vue过滤器做什么的(vue1.x和vue2.x这块的区别)
vue过滤器主要用于对渲染出来的数据进行格式化处理。例如:后台返回的数据性别用0和1表示,但渲染到页面上不能是0和1我得转换为“男“和”女”,这时就会用到过滤器,还有商品价格读取出来的是普通数值,例如:230035,但我要在前面加个货币符号和千分分隔等,例如变成:¥230,035,都得需要vue过滤器
创建过滤器,跟创建自定义指令类似,也有全局和局部过滤器的形式
全局过滤器:Vue.filter(‘过滤器名’,function(参数1,参数2,…) {
//………..
return 要返回的数据格式
})
局部过滤器:在组件内部添加filters属性来定义过滤器
fitlers:{
过滤器名(参数1,参数2,,…参数n) {
//………..
return 要返回的数据格式
}
}
51. vue组件通讯(即传值)?
第一种:父传子:主要通过props来实现的
具体实现:父组件通过import引入子组件,并注册,在子组件标签上添加要传递的属性,子组件通过props接收,接收有两种形式一是通过数组形式[‘要接收的属性’ ],二是通过对象形式{ }来接收,对象形式可以设置要传递的数据类型和默认值,而数组只是简单的接收
第二种:子传父:主要通过$emit来实现
具体实现:子组件通过通过绑定事件触发函数,在其中设置this.$emit(‘要派发的自定义事件’,要传递的值),$emit中有两个参数一是要派发的自定义事件,第二个参数是要传递的值
然后父组件中,在这个子组件身上@派发的自定义事件,绑定事件触发的methods中的方法接受的默认值,就是传递过来的参数
第三种:兄弟之间传值有两种方法:
方法一:通过event bus实现
具体实现:创建一个空的vue并暴露出去,这个作为公共的bus,即当作两个组件的桥梁,在两个兄弟组件中分别引入刚才创建的bus,在组件A中通过bus.$emit(’自定义事件名’,要发送的值)发送数据,在组件B中通过bus.$on(‘自定义事件名‘,function(v) { //v即为要接收的值 })接收数据
方法二:通过vuex实现
具体实现:vuex是一个状态管理工具,主要解决大中型复杂项目的数据共享问题,主要包括state,actions,mutations,getters和modules 5个要素,主要流程:组件通过dispatch到 actions,actions是异步操作,再actions中通过commit到mutations,mutations再通过逻辑操作改变state,从而同步到组件,更新其数据状态
方法三:使用全局的变量传递
在windons或document上声明或绑定数据,取值
52. vue中methods,computed,watch的区别?
computed是多对一的关系,而watch则是一对多的关系;
methods中都是封装好的函数,无论是否有变化只要触发就会执行
computed:是vue独有的特性计算属性,可以对data中的依赖项再重新计算,得到一个新值,应用到视图中,和methods本质区别是computed是可缓存的,也就是说computed中的依赖项没有变化,则computed中的值就不会重新计算,而methods中的函数是没有缓存的。Watch是监听data和计算属性中的新旧变化。
53. Vue中,怎么设置局部样式?原理?样式穿透?
css没有局部样式的概念,vue脚手架通过实现了,即在style标签上添加scoped,
scoped的实现原理:vue通过postcss给每个dom元素添加一个以data-开头的随机自定义属性、然后css根据属性选择器添加样式
第三方库的样式穿透:
less/sass穿透问题 >>> /deep/
声明全局样式,样式加后加 !important
将样式impoimport至App的上方
54. vue中 keep-alive 组件的作用
keep-alive:主要用于保留组件状态或避免重新渲染。
比如: 有一个列表页面和一个 详情页面,那么用户就会经常执行打开详情=>返回列表=>打开详情这样的话 列表 和 详情 都是一个频率很高的页面,那么就可以对列表组件使用<keep-alive></keep-alive>进行缓存,这样用户每次返回列表的时候,都能从缓存中快速渲染,而不是重新渲染。
1、属性:
include:字符串或正则表达式。只有匹配的组件会被缓存。
exclude:字符串或正则表达式。任何匹配的组件都不会被缓存。
2、用法:
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition>相似,<keep-alive>是一个抽象组件:它自身不会渲染一DOM 元素,也不会出现在父组件链中。
当组件在<keep-alive> 内被切换,在 2.2.0 及其更高版本中,activated 和 deactivated生命周期 将会在 树内的所有嵌套组件中触发。
55. vue中,props与data优先级
props > methods>data>computed>watch
56. webpack了解多少?
webpack是一个前端模块化打包构建工具,vue脚手架本身就用的webpack来构建的,webpack本身需要的入口文件通过entry来指定,出口通过output来指定,默认只支持js文件,其他文件类型需要通过对应的loader来转换,例如:less需要less,less-loader,sass需要sass-loader,css需要style-loader,css-loader来实现。当然本身还有一些内置的插件来对文件进行压缩合并等操作
插件:性能分析webpack-bundle-analyzer
你遇到过什么大的难题,怎么解决
职业规划