秋招前端面经

609 阅读27分钟

秋招前端面经

面了挺多公司,但是没几个大厂,不敢投,下面按照自己的经历分为国企和非国企和共性问题的面经


非国企

譬如招银网络、顺丰科技、4399等中小厂


JS\HTML\CSS

cookie、session、localStorage、sessionStorage区别

具体答案自行查找,我感觉每次回答都答不到面试官想要我答的点

回流(重排)与重绘

回流: 当渲染的一部分元素更改自己的宽高等,导致重新构建布局,就产生了回流。
重绘: 当一个元素自身的高度没改变,只改变了背景颜色的,发生重绘。
回流必定重绘,当重绘不一定回流。

避免回流和重绘方法

  1. 避免操作DOM
  2. 避免设置多层内联样式,因为每一个都会造成回流,样式合并在一个外部类,这样当该元素的class属性被操作时,只会产生一个reflow。
  3. 将需要多次回流的元素position属性设为absolute或fixed,这样该元素就会脱离文档流,它的变化不会影响其他元素变化。
  4. 避免使用table布局,
  5. 避免使用css的JavaScript表达式

闭包

概念:

红宝书:有权访问另一个函数作用域中的变量的函数

优点:

  1. 防止函数执行完后,变量被销毁,使其保存在内存中。
  2. 通过闭包和立即执行函数来封装函数, 全局变量可能会造成命名冲突,使用闭包不用担心这个问题,因为它是私有化,加强了封装性,这样保护变量的安全。

缺点:由于它是驻留在内存中,会增大内存使用量,使用不当很容易造成内存泄露。

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

kb.cnblogs.com/page/92320/

Cookie 和 Token

www.jianshu.com/p/ce9802589…

把token存储在localstorage等地方,通过http header 传递到服务器验证,不要使用http cookie机制,好处既能避开crsf跨站攻击,又能解决同源的跨域问题。

JWT 使用

  1. 首先,前端通过Web表单将自己的用户名和密码发送到后端的接口。这一过程一般是一个HTTP POST请求。建议的方式是通过SSL加密的传输(https协议),从而避免敏感信息被嗅探。
  2. 后端核对用户名和密码成功后,将用户的id等其他信息作为JWT Payload(负载),将其与头部分别进行Base64编码拼接后签名,形成一个JWT。形成的JWT就是一个形同lll.zzz.xxx的字符串。
  3. 后端将JWT字符串作为登录成功的返回结果返回给前端。前端可以将返回的结果保存在localStorage或sessionStorage上,退出登录时前端删除保存的JWT即可。
  4. 前端在每次请求时将JWT放入HTTP Header中的Authorization位。(解决XSS和XSRF问题)
  5. 后端检查是否存在,如存在验证JWT的有效性。例如,检查签名是否正确;检查Token是否过期;检查Token的接收方是否是自己(可选)。
  6. 验证通过后后端使用JWT中包含的用户信息进行其他逻辑操作,返回相应结果。
  • 和Session方式存储id的差异

Session方式存储用户id的最大弊病在于Session是存储在服务器端的,所以需要占用大量服务器内存,对于较大型应用而言可能还要保存许多的状态。一般而言,大型应用还需要借助一些KV数据库和一系列缓存机制来实现Session的存储。

而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。除了用户id之外,还可以存储其他的和用户相关的信息,例如该用户是否是管理员、用户所在的分组等。虽说JWT方式让服务器有一些计算压力(例如加密、编码和解码),但是这些压力相比磁盘存储而言可能就不算什么了。具体是否采用,需要在不同场景下用数据说话。

  • 单点登录  

Session方式来存储用户id,一开始用户的Session只会存储在一台服务器上。对于有多个子域名的站点,每个子域名至少会对应一台不同的服务器,例如:www.taobao.comnv.taobao.comnz.taobao.comlogin.taobao.com。所以如果要实现在login.taobao.com登录后,在其他的子域名下依然可以取到Session,这要求我们在多台服务器上同步Session。使用JWT的方式则没有这个问题的存在,因为用户的状态已经被传送到了客户端。

http1.0 和 1.1的区别(自己从简)

  1. 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
  2. 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
  3. 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
  4. Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
  5. 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

http1.x 和 2.0 的区别(自己从简)

  1. 二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
  2. 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
  3. header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
  4. 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。

https的原理

  1. 客户端发送请求到服务端
  2. 服务端返回公钥和证书
  3. 客户端验证证书合法性,客户端生成一个随机数密钥,通过证书中的公钥加密并发送给服务端。
  4. 服务端使用私钥解密,获取随机数密钥后,然后把内容通过该密钥进行对称加密。发送给客户端。
  5. 因为客户端也知道这个密钥,所以客户端可以还原信息。

可能会给中间人攻击,解决方法可以用第三方安全证书来认证。

判断对象的属性是原型的还是自己的

  1. hasOwnProperty()函数用于指示一个对象自身(不包括原型链)是否具有指定名称的属性。如果有,返回true,否则返回false。

  2. (属性名称 in 对象) 不管属性是原型的还是实例的,只要存在就返回ture否则返回false

那么我们可以利用这两个方法做一个对比,如果实例中没有且存在了这个属性,那么就是原型的

原型链

详细可以看juejin.im/post/684490…

下面简略说明:
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,如果还没有找到就会再的__proto__中查找,这样一层一层向上查找最后到object就会形成一个链式结构,我们称为原型链。

  1. 每一个构造函数都有一个prototype指针,他指向它的原型对象。
  2. 每一个原型对象都有一个constructor指针,它指向它的构造函数。
  3. 每一个对象都有一个__proto__指针,它指向它的原型对象。
  4. 对象的原型对象也有__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 ;

跨域,基本都考(一般会往深了问,具体过程自行查找)

同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议。

  1. jsonp:动态创建script标签,利用script标签不受同源政策约束来跨域获取数据(只能用get请求);
  2. cors跨域:前端正常请求附带Origin字段附带网址,服务端接收到后,更据自己的跨域规则,如果允许访问,响应头设置Access-Control-Allow-Origin字段。
  3. 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请求区别

  1. get在浏览器回退时是无害的,而post会再次请求
  2. get请求会被浏览器主动缓存,而post不会,除非手动设置
  3. get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留
  4. get 请求在url中传送的参数有长度限制,而post没有
  5. get参数通过url传递,poet放在request body中

盒子模型

元素的内容(content),元素的内边距(padding),元素的边框(border),元素的外边距(margin)四个部分

BFC

块格式化上下文(block formatting context) 是Web页面的可视化CSS渲染出的一部分。

BFC是页面CSS 视觉渲染的一部分,用于决定块盒子的布局及浮动相互影响范围的一个区域。
BFC的一个最重要的效果是,让处于BFC内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。
利用BFC可以闭合浮动,防止与浮动元素重叠。

BFC的创建方法
  1. 根元素或其它包含它的元素
  2. 浮动 (元素的float不为none)
  3. 绝对定位或固定定位元素 (元素的position为absolute或fixed)
  4. 行内块inline-blocks(元素的 display: inline-block)
  5. 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

  1. 输入url,常见的http协议的端口号是80,https是443
  2. 查看浏览器是否有缓存,其中分为强制缓存和相对缓存
  3. dns查询,用迭代查询和递归查询结合的方式查询
  4. TCP三次握手建立连接(可能会问三次握手的过程和目的)
  5. 浏览器向服务器发送HTTP请求
  6. 浏览器接收响应 服务器在收到浏览器发送的HTTP请求之后,处理完的结果以HTTP的Response对象返回,主要包括状态码,响应头,响应报文三个部分。
  7. 页面渲染,涉及浏览器的渲染过程和回流,重绘。

*柯里化

柯里化是把一个多参数函数转换为一个嵌套的一元函数的过程

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解析过程

  1. 浏览器根据地址去本身缓存中查找dns解析记录,如果有,则直接返回IP地址,否则浏览器会查找操作系统中(hosts文件)是否有该域名的dns解析记录,如果有则返回。
  2. 如果浏览器缓存和操作系统hosts中均无该域名的dns解析记录,或者已经过期,此时就会向域名服务器发起请求来解析这个域名。
  3. 请求会先到LDNS(本地域名服务器),让它来尝试解析这个域名,如果LDNS也解析不了,则直接到根域名解析器请求解析。
  4. 根域名解析器通过迭代查询和递归查询结合的方式来查找解析,最后返回相应的IP地址。

作用域链

作用域链就是一个有序的栈,保证对执行环境有权访问的所有变量和函数的有序访问。

其他具体自行查找,我也不能说具体。

执行上下文

不同于作用域链。

其他具体自行查找,我也不能说具体。

JS事件模型

DOM2事件模型

  1. 事件捕获阶段
  2. 事件处理阶段
  3. 事件冒泡阶段

dom.addEventListener(‘click’,function(){},true) 第一个参数侦听的事件,第二个参数为触发事件执行的方法,第三个true捕获阶段执行,false冒泡阶段执行

IE事件流:叫做事件冒泡。从点击的元素向上传播。用ele.attachEvent(‘onclick’, function(){ }); 只支持冒泡阶段

new()操作到底做了什么

  1. 创建一个新的空对象
  2. 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象)
  3. 执行构造函数中的代码(为这个新对象添加属性)
  4. 返回新对象
var obj = new Base();
// 等价于
var obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
//随后通过Base.prototype.xxx = () => {}为Base添加方法时,obj也同时拥有此方法

let const var区别

let:

  1. 不能重复声明一个变量
  2. 了他拥有块级作用域
  3. let声明不提前
  4. 总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”

const:

  1. 不能重复声明,要初始化
  2. 假如声明的是对象则允许修改对象的值

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处在中间,宽度自适应。

圣杯布局
  1. 圣杯布局是一种相对布局
  2. 将主体部分的三个子元素都设置左浮动
  3. 设置main宽度为width:100%,让其单独占满一行
  4. 设置left和right 负的外边距。负的margin-left会让元素沿文档流向左移动,如果负的数值比较大就会一直移动到上一行。
  5. 接下来只要把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布局
  1. 项目根据内容进行弹性布局
  2. 通过order属性设置排列顺序
  3. 通过项目属性flex-grow设置main的放大比例,将空余的空间用main来填充,使三个项目不满一整行;默认为0,也就是对剩余空间不做处理。
  4. 通过项目属性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水平垂直居中

水平居中:

  1. 行内元素:
text-align: center;
  1. 有宽度的块元素:
margin: 0 auto;

垂直居中:

  1. 单行内容垂直居中:
line-height: height; //height父级高度
  1. 绝对定位:
position: absolute;
top: 50%;
transform: translate(0, -50%);
  1. flex布局:
display: flex;
flex-direction: column;
justify-content: center;

方法很多:绝对定位、margin: auto、弹性布局、相对定位、table布局。
具体自行查找

CSS选择器优先级

  1. 在属性后面加!important会覆盖任何样式
  2. 作为style属性写在元素内的样式
  3. id选择器
  4. 类选择器
  5. 标签选择器
  6. 通配选择器

雪碧图(精灵图)

雪碧图又叫精灵图原理就是将一些小图标合并到一张图上,用css的背景定位来设置要显示的部分。

VUE

建议先阅读网上的源码解析

vue生命周期

  1. beforeCreate(创建前) 在数据观测和初始化事件还未开始
  2. created(创建后) 完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来
  3. beforeMount(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。
  4. mounted(载入后) 在el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。
  5. beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
  6. updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
  7. beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。
  8. destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
  9. activated:keep-alive组件被激活
  10. deactivited: keep-alive组件被移除

简述每个周期具体适合哪些场景?

  1. beforeCreate:可以在这加loading事件,在加载实例时触发。
  2. created:初始化完成时的事件写在这里,如在这里结束loading,异步请求也适合在这里调用。
  3. mounted:挂载元素,获取到dom节点。
  4. updated:如果对数据统一处理,在这里写上相应的函数。
  5. beforeDestroy:可以做一个确定停止事件的确认框。

聊聊你对Vue.js的template编译的理解?

先转化成AST树,再得到的render函数返回VNode(Vue的虚拟DOM节点)

  1. 通过compile编译器把template编译成AST语法树(abstract syntax tree 抽象语法树 即 源代码的抽象语法结构的树状表现形式),compile是createCompiler的返回值,createCompiler是用以创建编译器的。另外compile还负责合并option。
  2. AST会经过generate(将AST语法树转化成render funtion字符串的过程)得到render函数,render的返回值是VNode,VNode是Vue的虚拟DOM节点,里面有(标签名、子节点、文本等等)

vue数据双向绑定

采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

vue实现数据双向绑定主要步骤:

  1. 需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter。 这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化。
  2. compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。
  3. Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
    ①在自身实例化时往属性订阅器(dep)里面添加自己
    ②自身必须有一个update()方法
    ③待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
  4. MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

*更加详细请看源码和解析

vue组件间的数据通信

  1. 父组件与子组件传值 父组件传给子组件:子组件通过props方法接受数据;
    子组件传给父组件:$emit 方法传递参数
  2. 非父子组件间的数据传递,兄弟组件传值eventBus,就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。
    emit传值,emit 传值,on() 接收值。项目比较小时,用这个比较合适。
  3. 整个状态存储:vuex

vue路由

Vue的路由实现:hash模式 和 history模式

  1. hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;
    特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无害,hash不会重新加载页面。 hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
  2. history模式:history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。
    history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 www.xxx.com/items/id。后端… /items/id 的路由处理,将返回 404 错误。

*详细自行查找

vue-router导航钩子

  1. 全局导航钩子:
    (1)前置守卫:跳转前进行拦截。
    router.beforeEach(to, from, next)
    (2)后置钩子
    router.afterEach((to, from) => {})
  2. 组件内的钩子 beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
  3. 单独路由独享组件。 beforeEnter: (to, from ,next)

vuex中mutation 和action的区别

改变状态的方式,同步逻辑封装在mutation中,异步逻辑封装在action中。 详细自行查找

vue中引入组件的步骤

  1. components目录创建组件文件,如indexPage.vue。 注意:script一定要export default{}
  2. 在需要的页面(组件)引入组件(2种方式): (1)es6的import..from...
    import indexPage from '@/components/indexPage.vue'
    (2)CommonJS的require()
  3. 组件注册:注入到vue子组件的components属性上面,components{indexPage}
  4. 在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、存储过程……

计算机网络

……
这些建议查找网上面经,会比我的要详细很多,要是打算进国企,则一定要有好聊的实习和项目,还有一定的基础,基本上剩下的就看学历了。

先写到这,有缘日后再补充。