秋招前端面经
面了挺多公司,但是没几个大厂,不敢投,下面按照自己的经历分为国企和非国企和共性问题的面经
非国企
譬如招银网络、顺丰科技、4399等中小厂
JS\HTML\CSS
cookie、session、localStorage、sessionStorage区别
具体答案自行查找,我感觉每次回答都答不到面试官想要我答的点
回流(重排)与重绘
回流: 当渲染的一部分元素更改自己的宽高等,导致重新构建布局,就产生了回流。
重绘: 当一个元素自身的高度没改变,只改变了背景颜色的,发生重绘。
回流必定重绘,当重绘不一定回流。
避免回流和重绘方法
- 避免操作DOM
- 避免设置多层内联样式,因为每一个都会造成回流,样式合并在一个外部类,这样当该元素的class属性被操作时,只会产生一个reflow。
- 将需要多次回流的元素position属性设为absolute或fixed,这样该元素就会脱离文档流,它的变化不会影响其他元素变化。
- 避免使用table布局,
- 避免使用css的JavaScript表达式
闭包
概念:
红宝书:有权访问另一个函数作用域中的变量的函数
优点:
- 防止函数执行完后,变量被销毁,使其保存在内存中。
- 通过闭包和立即执行函数来封装函数, 全局变量可能会造成命名冲突,使用闭包不用担心这个问题,因为它是私有化,加强了封装性,这样保护变量的安全。
缺点:由于它是驻留在内存中,会增大内存使用量,使用不当很容易造成内存泄露。
Web前端性能优化
其实你可以从用户输入url经历的过程进行分析。
浏览器缓存:
首先会检查浏览器缓存,那就可以使用它。添加http缓存头Expires,使组件被缓存,下次访问的时候,就可以减少不必要的HTPP请求,从而提高加载速度。
DNS解析:
DNS解析,可以设置meta标签的http-equiv要求DNS预解析,比如遇到超链接就提前解析。
HTTP连接上:
常见的减少http请求如静态资源合并,js和css合并,雪碧图就不讲了。
服务器在完成 HTTP 请求之后不断开 TCP 连接而是挂起,后续有 HTTP 请求可以直接在这个 TCP 连接上发送;缺点是保持长连接会消耗服务端的资源。
HTTP/2 多路复用的特性允许多个 HTTP 请求在同一个 TCP 连接上发送,可以节省多次建立 TCP 连接的时间。
nginx 缓存blog.csdn.net/yu12377/art…
http Header
Cookie 和 Token
把token存储在localstorage等地方,通过http header 传递到服务器验证,不要使用http cookie机制,好处既能避开crsf跨站攻击,又能解决同源的跨域问题。
JWT 使用
- 首先,前端通过Web表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。
- 后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT。形成的JWT就是一个形同lll.zzz.xxx的字符串。
- 后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage或sessionStorage上,退出登录时前端删除保存的JWT即可。
- 前端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题)
- 后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确;检查Token是否过期;检查Token的接收方是否是自己(可选)。
- 验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。
- 和Session方式存储id的差异
Session方式存储用户id的最大弊病在于Session是存储在服务器端的,所以需要占用大量服务器内存,对于较大型应用而言可能还要保存许多的状态。一般而言,大型应用还需要借助一些KV数据库和一系列缓存机制来实现Session的存储。
而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。除了用户id之外,还可以存储其他的和用户相关的信息,例如该用户是否是管理员、用户所在的分组等。虽说JWT方式让服务器有一些计算压力(例如加密、编码和解码),但是这些压力相比磁盘存储而言可能就不算什么了。具体是否采用,需要在不同场景下用数据说话。
- 单点登录
Session方式来存储用户id,一开始用户的Session只会存储在一台服务器上。对于有多个子域名的站点,每个子域名至少会对应一台不同的服务器,例如:www.taobao.com,nv.taobao.com,nz.taobao.com,login.taobao.com。所以如果要实现在login.taobao.com登录后,在其他的子域名下依然可以取到Session,这要求我们在多台服务器上同步Session。使用JWT的方式则没有这个问题的存在,因为用户的状态已经被传送到了客户端。
http1.0 和 1.1的区别(自己从简)
- 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
- 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
- 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
- Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
- 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。
http1.x 和 2.0 的区别(自己从简)
- 二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
- 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
- header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
- 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。
https的原理
- 客户端发送请求到服务端
- 服务端返回公钥和证书
- 客户端验证证书合法性,客户端生成一个随机数密钥,通过证书中的公钥加密并发送给服务端。
- 服务端使用私钥解密,获取随机数密钥后,然后把内容通过该密钥进行对称加密。发送给客户端。
- 因为客户端也知道这个密钥,所以客户端可以还原信息。
可能会给中间人攻击,解决方法可以用第三方安全证书来认证。
判断对象的属性是原型的还是自己的
-
hasOwnProperty()函数用于指示一个对象自身(不包括原型链)是否具有指定名称的属性。如果有,返回true,否则返回false。
-
(属性名称 in 对象) 不管属性是原型的还是实例的,只要存在就返回ture否则返回false
那么我们可以利用这两个方法做一个对比,如果实例中没有且存在了这个属性,那么就是原型的
原型链
下面简略说明:
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,如果还没有找到就会再的__proto__中查找,这样一层一层向上查找最后到object就会形成一个链式结构,我们称为原型链。
- 每一个构造函数都有一个prototype指针,他指向它的原型对象。
- 每一个原型对象都有一个constructor指针,它指向它的构造函数。
- 每一个对象都有一个__proto__指针,它指向它的原型对象。
- 对象的原型对象也有__proto__指针指向上一个原型对象,最终__proto__指针一般指向object,因为它是基础object的。
这样链式的连接集合就构成了原型链。
继承(一般问优缺点)
原型继承(原型式继承)
在object()函数内部, 先创建一个临时性的构造函数, 然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例.
function object(o){
function F(){}
F.prototype = o;
return new F();
}
缺点:不是类式继承,而是原型式基础,缺少了类的概念
原型链继承
将父类实例作为子类的原型对象
function Parent () {
this.names = ['kevin', 'daisy'];
}
function Child () {
}
Child.prototype = new Parent();
var child1 = new Child();
child1.names.push('yayu');
console.log(child1.names); // ["kevin", "daisy", "yayu"]
var child2 = new Child();
console.log(child2.names); // ["kevin", "daisy", "yayu"]
缺点:所有子类的实例的原型都共享同一个父类实例的属性和方法。
构造函数继承
在函数中运行父级构造函数
// 子类
function Sub(){
Super.call(this)
this.property = 'Sub Property'
}
缺点:
父类函数没有共享,浪费内存。
无法继承原型链上的属性和方法。
组合继承
原型继承和构造函数继承的组合
// 子类
function Sub(){
Super.call(this)
this.property = 'Sub Property'
}
Sub.prototype = new Super()
// 注意这里new Super()生成的超类对象并没有constructor属性,故需添加上
Sub.prototype.constructor = Sub
缺点:父级构造函数被调用两次,子类实例也有两份,浪费内存。
实际上子类上会拥有超类的两份属性,只是子类的属性覆盖了原型对象上的属性。
寄生式继承(和原型式继承差不多)
原型式继承套个壳子,增加你要传入的参数。
function objectCreate(obj){
function F(){}
F.prototype = obj
return new F()
}
function createSubObj(superInstance){
var clone = objectCreate(superInstance)
clone.property = 'Sub Property'
return clone
}
缺点:依旧没有类的概念
寄生组合式继承
在子构造函数中执行父级函数,并创建Object.create(父级的原型对象)复值给obj,再修改obj的constructor的指针指向子构造函数,最后obj作为子构造函数的原型对象。
function Sub(){
Super.call(this);
}
var proto = Object.create(Super.prototype);
proto.constructor = Sub;
Sub.prototype = proto ;
跨域,基本都考(一般会往深了问,具体过程自行查找)
同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议。
- jsonp:动态创建script标签,利用script标签不受同源政策约束来跨域获取数据(只能用get请求);
- cors跨域:前端正常请求附带Origin字段附带网址,服务端接收到后,更据自己的跨域规则,如果允许访问,响应头设置Access-Control-Allow-Origin字段。
- html5的postMessage方法跨域:不能和服务端交换数据,只能在两个窗口(iframe)之间交换数据。A页面有B页面的引用。A用postMessage方法发送消息,B页面通过message事件监听并接受消息:
nginx 配置跨域blog.csdn.net/yujia_666/a…
状态码
1xx:指示信息–表示请求已接收.
2xx:成功-请求已接受并返回响应头
200:请求已成功,返回响应头。
3xx:重定向–要完成请求必须进行更进一步的操作。
301:请求的资源已被永久移到新位置。
302:临时重定向
304:缓存的内容并未改变。
4xx:客户端错误–请求有语法错误或请求无法实现。
400:请求无效,前端提交数据的字段名称或者是字段类型和后台的实体类不一致。
401:请求要身份验证。
403:资源不可用。
404:找不到页面。
5xx:服务器端错误–服务器未能实现合法的请求。
500:服务器遇到未知状况,无法处理。
503:服务器过载或维护。
post和get请求区别
- get在浏览器回退时是无害的,而post会再次请求
- get请求会被浏览器主动缓存,而post不会,除非手动设置
- get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留
- get 请求在url中传送的参数有长度限制,而post没有
- get参数通过url传递,poet放在request body中
盒子模型
元素的内容(content),元素的内边距(padding),元素的边框(border),元素的外边距(margin)四个部分
BFC
块格式化上下文(block formatting context) 是Web页面的可视化CSS渲染出的一部分。
BFC是页面CSS 视觉渲染的一部分,用于决定块盒子的布局及浮动相互影响范围的一个区域。
BFC的一个最重要的效果是,让处于BFC内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。
利用BFC可以闭合浮动,防止与浮动元素重叠。
BFC的创建方法
- 根元素或其它包含它的元素
- 浮动 (元素的float不为none)
- 绝对定位或固定定位元素 (元素的position为absolute或fixed)
- 行内块inline-blocks(元素的 display: inline-block)
- overflow的值不为visible的元素
边距重叠
如果子div中有margin-top会外层div塌陷。 解决设置:父设置,overflow:hidden即可。
深拷贝的方法,(说了JSON.stringfiy+JSON.parse)
1:
var copy = JSON.parse(JSON.stringify(person))
缺点:1.无法拷贝对象中的function、undefined、null、RegExp属性
2:
function deepCopy(obj) {
var result = Array.isArray(obj) ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object' && obj[key]!==null) {
result[key] = deepCopy(obj[key]); //递归复制
} else {
result[key] = obj[key];
}
}
}
return result;
}
缺点就是复杂点
访问url
- 输入url,常见的http协议的端口号是80,https是443
- 查看浏览器是否有缓存,其中分为强制缓存和相对缓存
- dns查询,用迭代查询和递归查询结合的方式查询
- TCP三次握手建立连接(可能会问三次握手的过程和目的)
- 浏览器向服务器发送HTTP请求
- 浏览器接收响应 服务器在收到浏览器发送的HTTP请求之后,处理完的结果以HTTP的Response对象返回,主要包括状态码,响应头,响应报文三个部分。
- 页面渲染,涉及浏览器的渲染过程和回流,重绘。
*柯里化
柯里化是把一个多参数函数转换为一个嵌套的一元函数的过程
const addCurried = function(x){
return function(y){
return x + y;
}
}
// 使用方法
addCurried(4)(4)
// 8
能够进行延迟计算,就像add(1)(2)一样,1比2先传入,2就会被延迟计算,在特定的场景里,有一定的应用意义。
节流防抖
函数节流
用在连续点击div时,
是为了限制函数一段时间内只能执行一次,在延时的时间内,方法若被触发,则直接退出方法。
let throttle = (func, wait) => {
let timer;
return function() {
if(timer) {
return ;
}
var self = this;
var args = arguments;
timer = setTimeout(function() {
func.apply(self, args);
timer = null;
}, wait)
}
}
函数防抖
用在搜索输入时,
函数防抖在执行目标方法时,会等待一段时间。当又执行相同方法时,若前一个定时任务未执行完,则 clear 掉定时任务,重新定时。
let debounce = function(func,wait) {
let timer;
return function(){
let args = arguments;
var self = this;
clearTimeout(timer);
timer = setTimeout(function(){
func.apply(self,args);
}, wait);
}
}
浏览器缓存(http缓存)
考察控制字段,这个不熟,每次答感觉都答不到面试官的点上,自行查找合适的解释。
*域名收敛域名发散
DNS解析过程
- 浏览器根据地址去本身缓存中查找dns解析记录,如果有,则直接返回IP地址,否则浏览器会查找操作系统中(hosts文件)是否有该域名的dns解析记录,如果有则返回。
- 如果浏览器缓存和操作系统hosts中均无该域名的dns解析记录,或者已经过期,此时就会向域名服务器发起请求来解析这个域名。
- 请求会先到LDNS(本地域名服务器),让它来尝试解析这个域名,如果LDNS也解析不了,则直接到根域名解析器请求解析。
- 根域名解析器通过迭代查询和递归查询结合的方式来查找解析,最后返回相应的IP地址。
作用域链
作用域链就是一个有序的栈,保证对执行环境有权访问的所有变量和函数的有序访问。
其他具体自行查找,我也不能说具体。
执行上下文
不同于作用域链。
其他具体自行查找,我也不能说具体。
JS事件模型
DOM2事件模型
- 事件捕获阶段
- 事件处理阶段
- 事件冒泡阶段
dom.addEventListener(‘click’,function(){},true) 第一个参数侦听的事件,第二个参数为触发事件执行的方法,第三个true捕获阶段执行,false冒泡阶段执行
IE事件流:叫做事件冒泡。从点击的元素向上传播。用ele.attachEvent(‘onclick’, function(){ }); 只支持冒泡阶段
new()操作到底做了什么
- 创建一个新的空对象
- 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回新对象
var obj = new Base();
// 等价于
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
//随后通过Base.prototype.xxx = () => {}为Base添加方法时,obj也同时拥有此方法
let const var区别
let:
- 不能重复声明一个变量
- 了他拥有块级作用域
- let声明不提前
- 总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”
const:
- 不能重复声明,要初始化
- 假如声明的是对象则允许修改对象的值
promise(!important)
原理
优缺点
适用场景
自己代码实现
了解async和await
不写了,太多
自己对请求做多一层处理,针对不同状态码响应
css画一个三角形
.triangle_border_up{
width:0;
height:0;
border-width: 30px; /*上右下左 上为0为上三角形*/
border-style:solid;
border-color:transparent transparent transparent #333;/*透明 透明 透明 灰*/
}
三栏布局,两边定宽中间自适应(圣杯布局、双飞翼布局)
实现三栏水平布局,其中left、right分别位于左右两侧,left宽度为200px,right宽度为300px,main处在中间,宽度自适应。
圣杯布局
- 圣杯布局是一种相对布局
- 将主体部分的三个子元素都设置左浮动
- 设置main宽度为width:100%,让其单独占满一行
- 设置left和right 负的外边距。负的margin-left会让元素沿文档流向左移动,如果负的数值比较大就会一直移动到上一行。
- 接下来只要把left和right分别移动到这两个留白就可以了。可以使用相对定位移动 left和right部分。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>实现三栏水平布局之圣杯布局</title>
<style type="text/css">
.container {
padding: 0 300px 0 200px;
}
.left, .main, .right {
position: relative;
min-height: 130px;
float: left;
}
.left {
left: -200px;
margin-left: -100%;
background: green;
width: 200px;
}
.right {
right: -300px;
margin-left: -300px;
background-color: red;
width: 300px;
}
.main {
background-color: blue;
width: 100%;
}
</style>
</head>
<body>
<div class="container">
<div class="main">main</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
</body>
</html>
双飞翼布局
圣杯布局和双飞翼布局解决问题的方案在前一半是相同的,也就是三栏全部float浮动,但左右两栏加上负margin让其跟中间栏div并排,以形成三栏布局。
双飞翼布局比圣杯布局多使用了1个div,少用大致4个css属性(圣杯布局container的 padding-left和padding-right这2个属性,加上左右两个div用相对布局position: relative及对应的right和left共4个属性,;而双飞翼布局子div里用margin-left和margin-right共2个属性,比圣杯布局思路更直接和简洁一点。简单说起来就是:双飞翼布局比圣杯布局多创建了一个div,但不用相对布局了。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>实现三栏水平布局之双飞翼布局</title>
<style type="text/css">
.left, .main, .right {
float: left;
min-height: 130px;
text-align: center;
}
.left {
margin-left: -100%;
background: green;
width: 200px;
}
.right {
margin-left: -300px;
background-color: red;
width: 300px;
}
.main {
background-color: blue;
width: 100%;
}
.content{
margin: 0 300px 0 200px;
}
</style>
</head>
<body>
<div class="container">
<div class="main">
<div class="content">main</div>
</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
</body>
</html>
flex布局
- 项目根据内容进行弹性布局
- 通过order属性设置排列顺序
- 通过项目属性flex-grow设置main的放大比例,将空余的空间用main来填充,使三个项目不满一整行;默认为0,也就是对剩余空间不做处理。
- 通过项目属性flex-basis 设置left和right的固定宽度
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>实现三栏水平布局之Flex布局</title>
<style type="text/css">
.container{
display: flex;
min-height: 130px;
}
.main{
flex-grow: 1;
background-color: blue;
}
.left{
order: -1;
flex-basis: 200px;
background-color: green;
}
.right{
flex-basis: 300px;
background-color: red;
}
</style>
</head>
<body>
<div class="container">
<div class="main">main</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
</body>
</html>
绝对定位布局
绝对定位使元素的位置与文档流无关,因此不占据空间。这一点与相对定位不同,相对定位实际上被看作普通流定位模型的一部分,因为元素的位置相对于它在普通流中的位置。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>实现三栏水平布局之绝对定位布局</title>
<style type="text/css">
.container{
position: relative;
}
.main,.right,.left{
top: 0;
height: 130px;
}
.main{
margin: 0 300px 0 200px;
background-color: blue;
}
.right{
position: absolute;
width: 300px;
right: 0;
background-color: red;
}
.left{
position: absolute;
width: 200px;
background-color: green;
left: 0;
}
</style>
</head>
<body>
<div class="container">
<div class="main">main</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
</body>
</html>
CSS水平垂直居中
水平居中:
- 行内元素:
text-align: center;
- 有宽度的块元素:
margin: 0 auto;
垂直居中:
- 单行内容垂直居中:
line-height: height; //height父级高度
- 绝对定位:
position: absolute;
top: 50%;
transform: translate(0, -50%);
- flex布局:
display: flex;
flex-direction: column;
justify-content: center;
方法很多:绝对定位、margin: auto、弹性布局、相对定位、table布局。
具体自行查找
CSS选择器优先级
- 在属性后面加!important会覆盖任何样式
- 作为style属性写在元素内的样式
- id选择器
- 类选择器
- 标签选择器
- 通配选择器
雪碧图(精灵图)
雪碧图又叫精灵图原理就是将一些小图标合并到一张图上,用css的背景定位来设置要显示的部分。
VUE
建议先阅读网上的源码解析
vue生命周期
- beforeCreate(创建前) 在数据观测和初始化事件还未开始
- created(创建后) 完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来
- beforeMount(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。
- mounted(载入后) 在el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。
- beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
- updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
- beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。
- destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
- activated:keep-alive组件被激活
- deactivited: keep-alive组件被移除
简述每个周期具体适合哪些场景?
- beforeCreate:可以在这加loading事件,在加载实例时触发。
- created:初始化完成时的事件写在这里,如在这里结束loading,异步请求也适合在这里调用。
- mounted:挂载元素,获取到dom节点。
- updated:如果对数据统一处理,在这里写上相应的函数。
- beforeDestroy:可以做一个确定停止事件的确认框。
聊聊你对Vue.js的template编译的理解?
先转化成AST树,再得到的render函数返回VNode(Vue的虚拟DOM节点)
- 通过compile编译器把template编译成AST语法树(abstract syntax tree 抽象语法树 即 源代码的抽象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以创建编译器的。另外compile还负责合并option。
- AST会经过generate(将AST语法树转化成render funtion字符串的过程)得到render函数,render的返回值是VNode,VNode是Vue的虚拟DOM节点,里面有(标签名、子节点、文本等等)
vue数据双向绑定
采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
vue实现数据双向绑定主要步骤:
- 需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter。 这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化。
- compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。
- Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
①在自身实例化时往属性订阅器(dep)里面添加自己
②自身必须有一个update()方法
③待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。 - MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
*更加详细请看源码和解析
vue组件间的数据通信
- 父组件与子组件传值
父组件传给子组件:子组件通过props方法接受数据;
子组件传给父组件:$emit 方法传递参数 - 非父子组件间的数据传递,兄弟组件传值eventBus,就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。
on() 接收值。项目比较小时,用这个比较合适。 - 整个状态存储:vuex
vue路由
Vue的路由实现:hash模式 和 history模式
- hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;
特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无害,hash不会重新加载页面。 hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。 - history模式:history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。
history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 www.xxx.com/items/id。后端… /items/id 的路由处理,将返回 404 错误。
*详细自行查找
vue-router导航钩子
- 全局导航钩子:
(1)前置守卫:跳转前进行拦截。
router.beforeEach(to, from, next)
(2)后置钩子
router.afterEach((to, from) => {}) - 组件内的钩子 beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
- 单独路由独享组件。 beforeEnter: (to, from ,next)
vuex中mutation 和action的区别
改变状态的方式,同步逻辑封装在mutation中,异步逻辑封装在action中。 详细自行查找
vue中引入组件的步骤
- components目录创建组件文件,如indexPage.vue。 注意:script一定要export default{}
- 在需要的页面(组件)引入组件(2种方式):
(1)es6的import..from...
import indexPage from '@/components/indexPage.vue'
(2)CommonJS的require() - 组件注册:注入到vue子组件的components属性上面,components{indexPage}
- 在template视图view中使用。
注意:命名时如果是indexPage,使用的时候用index-page
vue实现流程
看源码解析
1、第一步:解析模板成render函数
template
2、第二步:响应式开始监听
object.defineProperty
data属性代理到vm上
3、第三步:首次渲染,显示页面,且绑定依赖
(1)为何要监听get,直接监听set不行吗?
①data中有很多属性,有些被用到,有些可能不被用到(data中没有人访问,就不会用get,如没有{{aaa}}指的就是aaa没有被访问)
②被用到的会走到get,不被用到的不会走到get
③未走到get中的属性,set的时候也无需关心
④避免不必要的重复渲染
4、第四步:data属性变化,触发rerender
defineProperty, get, set
(1)修改属性,被响应式的set监听到
(2)set中执行updateComponent
(3)updateComponent重新执行vm._render()
(4)生成的vnode和prevVnode,通过Patch进行对比
渲染到html
国企
一般问项目还有计算机基础,具体看共性问题
都会问的问题
数据结构
排序、树、图……
数据库
mysql、mongodb、存储过程……
计算机网络
……
这些建议查找网上面经,会比我的要详细很多,要是打算进国企,则一定要有好聊的实习和项目,还有一定的基础,基本上剩下的就看学历了。
先写到这,有缘日后再补充。