vue虚拟dom

在vue2.0渲染层做了根本性的改动,那就是引入了虚拟dom。vdom算法是基于snabbdom算法所做的修改
每次更新视图的时候都会使用vdom
源码分析:vm实例挂载到dom上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
src/core/instance/init.js
Vue.prototype._init = function(){
vm.$mount(vm.$options.el)
}
实际上调用的是src/core/instance/lifecycle.js中的mountComponent方法
export function mountComponent(vm:Component,el:?Element,hydrating?:boolean):Component{
vm.$el = el;
if(!vm.$options.render){
vm.$options.render = createEmptyVNode
}
callHook(vm,'beforeMount')
let updateComponent
if(process.env.NODE_ENV !== 'production' && config.performance && mark){

}else{
updateComponent = ()=>{
//vm._render方法会返回一个新的vnode,vm._update就用这个新的vnode和老的vnode进行diff
vm._update(vm._render(),hydrating)
}
}
//在求值的过程中this.value = this.lazy ? undefined : this.get(),
//会调用this.get()方法,因此在实例化的过程当中Dep.target会被设为这个watcher
vm._watcher = new Watcher(vm,updateComponent,noop)
hydrating = false
if(vm.$vnode == null){
vm._isMounted = true
callHook(vm,'mounted')
}
return vm
}

一旦model中的响应式的数据发生了变化,这些响应式的数据所维护的dep数组便会调用dep.notify()方法完成所有依赖遍历执行的工作,这里面就包括了视图的更新即updateComponent方法,它是在mountComponent中的定义的。
完成视图的更新工作事实上就是调用了vm._update方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Vue.prototype._update = function(vnode: VNode, hydrating?: boolean){
const vm:Component = this
if(vm._isMounted){
callHook(vm,'beforeUpdate')
}
const prevEL = vm.$el
const prevVnode = vm._vnode
const prevActiveInstance = activeInstance
activeInstance = vm
//新的vnode
vm._vnode = vnode
if(!prevVnode){
vm.$el = vm.__patch__(vm.$el,vnode,bydrating,false,
vm.$options._parentElm,
vm.$options._refElm
)
}else{
vm.$el = vm.__patch__(prevVnode,vnode)
}
activeInstance = prevActiveInstance
if(prevEL){
prevEL.__vue__ = null
}
if(vm.$el){
vm.$el.__vue__ = vm
}
if(vm.$vnode && vm.$parent && vm.$node === vm.$parent._node){
vm.$parent.$el = vm.$el
}
}

vue源码分析

3.0
vue3.0的代码从flow迁移到typescript上了,用typescript完全重写了。
代码重构的点:内部模块节藕;编译器重构,插件化设计
平台支持:vue3.0将会提供一个custom render API:createRender.createRender函数更好的支持开发者去用vue语法写支持多端的代码
vue hooks 大概率取代了mixins
会有一个专门的版本自动降级为用Object.defineproperty()的get、set拦截处理数据,并对一些新的ie不支持的用法做出警告
2.x
基本模块:准备工作-数据驱动-组件化-响应式原理-编译-扩展-vuerouter-vuex
一、Flow
Flow是Facebook出品的JavaScript静态类型检查工具。Vue源码利用了Flow做静态类型检查。
目的:解决编译阶段不被发现,运行阶段才能暴露的隐患bug,增强代码的可维护性和可读性
引入时机:Vue2.0重构时,已包含功能(es6语法,eslint代码风格)
选择Flow的原因:Babel和ESLint都有对应的Flow插件以支持语法,改动成本小
类型检查是当前动态语言的发展趋势,在编译期尽早发现(由类型错误引起的)bug
类型检查方式:类型推断、类型注释(Array<T>,string | number)
若想任意类型 T 可以为 null 或者 undefined,只需类似如下写成 ?T 的格式即可。

1
2
3
4
5
6
7
8
9
10
11
12
//类型推断:下面的写法编译时就会报错,不会等到方法调用时
function split(str){
return str.split('');
}
split(11);//split方法只接收string类型

//类型注释,即给参数或变量设置默认类型
function add(x:number,y:number):number{
return x+y
}
var arr:Array<number> = [1,2,3];
var b:string | number = 123;

二、源码目录结构src
compiler(编译相关):把模版解析成ast语法树,ast语法树优化,代码生成等功能。编译是一项耗性能的工作,推荐使用webpack、vue-loader在构建时编译(离线编译),不要等到运行时
core(核心代码):内置组件、全局API封装、vue实例化,观察者,虚拟dom、工具函数
platforms(各平台的支持):两个目录代表两个主要入口
server(服务器端渲染)
sfc(.vue文件解析)
shared(共享文件)

面向对象

1.类与实例:类的声明,创建实例

1
2
3
4
5
6
7
8
9
10
11
//传统方式:构造函数
function Student(name){
this.name = name;
}

//es6语法
class Student{
constructor(){
this.name = name;
}
}

2.继承的原理:原型链
3.实现继承的方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//借助构造函数实现继承:不能继承原型对象中的方法(部分继承)
function Parent(){
this.name = "parent";
}
function Child(){
Parent.call(this);//或apply
this.age = '18';
}

//借助原型链实现继承:不能实现隔离,修改原型链上的属性就会所有实例都改变
function Parent(){
this.name = "parent";
}
function Child(){
this.age = '18';
}
Child.prototype = new Parent();

//组合方式:构造函数执行2次
function Parent(){
this.name = "parent";
}
function Child(){
Parent.call(this);//或apply
this.age = '18';
}
Child.prototype = new Parent();

//组合优化:此时创建的实例既是child的实例,又是parent的实例,区别不了,实例的constructor指向parent
function Parent(){
this.name = "parent";
}
function Child(){
Parent.call(this);//或apply
this.age = '18';
}
Child.prototype = Parent.prototype;

//最终版
function Parent(){
this.name = "parent";
}
function Child(){
Parent.call(this);//或apply
this.age = '18';
}
//创建中间对象
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child;

vue详解

1、vue与其它框架的异同点
与react相似之处:
使用虚拟dom;提供了响应式(Reactive)和组件化(Composable)的视图组件;
将注意力集中保持在核心库,而将其它功能如路由和全局状态管理交给相关的库
2、vue-router之编程式导航

1
2
3
4
5
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})

// 带查询参数,变成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

注意:如果提供了 path,params 会被忽略
3、vuex
Vuex 背后的基本思想:通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation,可以追踪状态变化。

1
2
3
4
5
6
 mutations: {
increment (state) {
state.count++
}
}
store.commit('increment')

dom事件

  1. dom事件级别:dom0,dom2,dom3
    dom0: el.onclick = function(){}
    dom2: el.addEventListener(‘click’,function(){},false)
    dom3: el.addEventListener(‘keyup’,function(){},false)
    dom1中没有定义事件相关的东西,所以说事件级别没有dom1,dom3中事件类型增加了许多
  2. dom事件模型:事件捕获(从上向下),事件冒泡
  3. dom事件流:捕获阶段、目标阶段、冒泡阶段
  4. dom事件捕获的具体流程
    window-document-html(document.documentElement)-body-目标元素
  5. event对象的常见应用
    e.preventDefault()、e.stopPropagation()、e.stopImmediatePropagation():事件响应优先级、e.target、e.currentTarget
    事件委托(事件代理)的写法:$(ul).delegate(‘li’,click,fun);
  6. 自定义事件
    var eve = new Event(‘custome’);
    或者var eve = new CustomEvent(‘custome’,obj);//可以接受参数
    el.addEventListener(‘custome’,function(){
    console.log(‘custome’);
    },false);
    el.dispatchEvent(eve);

css盒模型

  1. css盒模型:标准盒模型/IE盒模型
  2. 两种盒模型的区别:标准盒模型width只包括内容部分,IE盒模型width=内容+padding+border
  3. css如何设置这两种样式:box-sizing:content-box/border-box
  4. js获取盒模型的宽高:dom.style.width/height(只能取到行内样式的宽高)
    dom.currentStyle.width/height(只有ie支持)
    window.getComputedStyle(dom).width/height(兼容性好)
    dom.getBoundingClientRect().width/height(计算元素的绝对位置)
  5. 解释边距重叠
    父子元素边距重叠,兄弟元素边距重叠
  6. 什么是BFC?原理?创建BFC的几种方式,使用场景
    BFC(块级格式化上下文:边距重叠解决方案)
    原理:1.BFC元素不会与浮动元素重叠2.浮动的子元素参与计算高度
    设置overflow:auto/hidden,float不为none,position:absolute/fixed,display:,
  7. 清除浮动(BFC清除浮动)

jQuery源码解析

jQuery2.0之后不再支持IE6/7/8,从2.1版开始jQuery支持通过AMD模块化分
jQuery的核心理念:The Write Less,Do More.
image
任何库与框架设计的第一个要点就是解决命名空间与变量污染的问题。jQuery就是利用了JavaScript函数作用域的特性,采用立即调用表达式包裹了自身的方法来解决这个问题。
jQuery兼容的具体策略:针对高级的浏览器,我们当前很乐意用DOMContentLoaded事件了,省时省力。
对于旧的IE,document.attachEvent
jQuery的整体架构:
变量、常用正则初始化
工具方法$.fn
$.ready()
复杂选择器Sizzle
回调对象:对函数的统一管理$.Callback()
延迟对象:对异步的统一管理$.Deferred()
浏览器功能性检测$.support
数据存储$.data
队列方法:执行顺序的管理queue()|dequeue()
对元素属性的操作:attr()、prop()、val()、addClass()等
事件操作的相关方法:on()、trigger()
DOM操作
样式操作:css()
Ajax()
动画animate()
位置和尺寸offset()
模块化
window.jQuery = window.$ = jQuery;
jQuery 闭包结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 用一个函数域包起来,就是所谓的沙箱
// 在这里边 var 定义的变量,属于这个函数域内的局部变量,避免污染全局
// 把当前沙箱需要的外部变量通过函数参数引入进来
// 只要保证参数对内提供的接口的一致性,你还可以随意替换传进来的这个参数
(function(window, undefined) {
// jQuery 代码
})(window);
jQuery 具体的实现,都被包含在了一个立即执行函数构造的闭包里面,为了不污染全局作用域,只在后面暴露 $ 和 jQuery 这 2 个变量给外界,尽量的避开变量冲突。
jQuery 在这里有一个针对压缩优化细节,使用这种书写方式,在代码压缩的时候,window 和 undefined 都可以压缩为 1 个字母并且确保它们就是 window 和 undefined。
// 压缩策略
// w -> windwow , u -> undefined
(function(w, u) {

})(window);

内部实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
jQuery = function(selector, context) {
// The jQuery object is actually just the init constructor 'enhanced'
// 看这里,实例化方法 jQuery() 实际上是调用了其拓展的原型方法 jQuery.fn.init
return new jQuery.fn.init(selector, context, rootjQuery);
},

// jQuery.prototype 即是 jQuery 的原型,挂载在上面的方法,即可让所有生成的 jQuery 对象使用
jQuery.fn = jQuery.prototype = {
// 实例化化方法,这个方法可以称作 jQuery 对象构造器
init: function(selector, context, rootjQuery) {
// ...
}
}
// 这一句很关键,也很绕
// jQuery 没有使用 new 运算符将 jQuery 实例化,而是直接调用其函数
// 要实现这样,那么 jQuery 就要看成一个类,且返回一个正确的实例
// 且实例还要能正确访问 jQuery 类原型上的属性与方法
// jQuery 的方式是通过原型传递解决问题,把 jQuery 的原型传递给jQuery.prototype.init.prototype
// 所以通过这个方法生成的实例 this 所指向的仍然是 jQuery.fn,所以能正确访问 jQuery 类原型上的属性与方法
jQuery.fn.init.prototype = jQuery.fn;

html页面布局

一、高度已知(200px),左右宽度固定300px,右边自适应的三栏布局
1、浮动:先写浮动的元素(左右),再写标准文档流元素
2、绝对定位:中间设置left:300px;right:300px;相当于设置了宽度
3、flex布局
4、table布局:父元素设置display:table;子元素设置display:table-cell;
5、网格布局:父元素设置display:grid;grid-template-columns:300px auto 300px;grid-template-rows:200px;
二、高度未知,左右宽度固定300px,右边自适应,且左右高度能够跟着父容器变化的三栏布局
1、flex布局
2、table布局:父元素设置display:table;子元素设置display:table-cell;

web前端跳槽面试技巧

基础流程:页面布局css盒模型DOM事件-HTTP协议-面向对象原型链-通信-安全-算法
http协议类:请求-应答模式
1、 http协议的主要特点:简单快速,灵活,无连接,无状态
2、 http报文的组成部分:
请求报文:请求行(GET/HTTP/1.1)+请求头(一系列键值对)+空行+请求体
响应报文:状态行(HTTP/1.1 200 OK)+响应头+空行+响应体
3、 http方法:get/post/put/delete/head
4、 post和get的区别:
浏览器回退重复提交(post)/无害(get)
get产生的url可以被收藏,post不可以
get会被浏览器主动缓存,post不会
get url有长度限制,因此不能携带太多参数
get没有post安全,不能存放敏感信息
get请求通过url传递参数,post放在request body中
5、 http状态码
1XX:
2xx:200,206
3xx:301(Moved Permanently),304(Not Modified)
4xx:400,401,403,404,405
5xx:500,503
6、 持久链接/管线化:Keep-alive(1.1)

通信类
1、同源策略及限制:协议、域名、端口号相同
跨域:跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。
跨域带来的问题:cookie、localstorage和indexDB无法读取;DOM 和 Js对象无法获得;ajax请求不能发送
有三个标签允许跨域请求资源:

1
<img src=XXX> 2.<link href=XXX> 3.<script src=XXX>

所有的跨域都必须经过信息提供方的允许才能完成
2、前后端如何通信:ajax、webSocket、cors
3、如何创建Ajax
4、跨域通信的几种方式:jsonp,hash,postMessage,webSocket,cors
跨域解决方案
jsonp只支持get请求
实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
响应头添加header(“Access-Control-Allow-Origin:*”);默认地址是网站本身
cors要求前端浏览器>10,
websocket在建立时需要借助http协议,连接建立好之后client与server之间的双向通信就与http无关了
原生websocketAPI使用起来不太方便,我们使用Socket.io

安全类: CSRF、XSS
CSRF(Cross-site request forgrey):跨站请求伪造
攻击原理:转发cookie
防御措施:token验证、referer验证、隐藏令牌
XSS(Cross-site scripting):跨域脚本攻击
攻击原理:脚本注入

算法类
排序
堆栈、队列、链表
递归
波兰式和逆波兰式

二面:渲染机制-js运行机制-页面性能-错误监控

  1. 什么是doctype及作用?
  2. 浏览器渲染过程
    image
  3. 重排reflow
  4. 重绘repaint
  5. 布局layout
  1. js单线程
  2. 任务队列
  3. event loop

  4. 提升页面性能的方法有哪些?
    A.资源压缩合并,减少http请求
    B.非核心代码的异步加载-异步加载的方式有哪些-异步加载的区别
    异步加载的方式:1)动态脚本加载 2)defer 3)async
    异步加载的区别:
    defer在html解析完毕后才执行,多个按照书写顺序加载
    async是在加载完之后立即执行,执行顺序与加载顺序无关
    C.利用浏览器缓存-缓存的分类-缓存的原理
    缓存的分类:强缓存、协商缓存
    强缓存:Expires(绝对时间)、Cache-Control(相对时间max-age=3600)
    协商缓存:Last-Modified If-Modified-Since Etag If-None-Match
    D.使用cdn
    E.dns预解析

原型链

一、创建对象的几种方式:
1、创建单个对象(Object 构造函数或对象字面量),缺点:创建很多对象,会产生大量的重复代码

1
2
3
4
5
6
7
8
9
10
//Object 构造函数
var person = new Object();
person.name = "Nicholas";
person.age = 29;

//对象字面量
var person = {
name: "Nicholas",
age: 29
};

2、工厂模式(解决创建很多对象,会产生大量的重复代码的问题)

1
2
3
4
5
6
7
8
function createPerson(name, age){
var o = new Object();
o.name = name;
o.age = age;
return o;
}
var person1 = createPerson("Nicholas", 29);
var person2 = createPerson("Nicholas", 29);

3、构造函数模式

1
2
3
4
5
6
function Person(name, age){
this.name = name;
this.age = age;
}
var person1 = new Person("Nicholas", 29);
var person2 = new Person("Nicholas", 29);

4、Object.create({name:’p’}),创建了一个空对象,新对象的proto指向{name:’p’}
二、原型、构造函数、实例、原型链
image
三、instanceof的原理
image
四、new的时候都做了什么?
创建对象-改变this指向-执行构造函数中的代码-返回新对象