Vue 原理(大厂必考!!!)

面试为何会考察原理?

  • 之前然知其所以然
  • 了解原理,才能应用的更好
  • 大厂造轮子

面试中如何考察?以何种方式?

  • 考察重点,而不是考察细节。掌握好2/8原则
  • 和使用相关联的原理,如vdom、模板渲染
  • 整体流程是否去全面?热门技术是否有深度?

Vue原理包括哪些?

image.png

一、 组件化和MVVM

概念介绍:组件化基础

面试官不会这么直接的问,他会问你什么是MVVM模型?

这道题这么回答:

第一:历史渊源: “很久以前”就有组件化

asp,jsp php 的最早的做前端的时候,就已经存在组件化了,
而且node.js 中也存在组件化,下面用nodejs 做的一个项目举例(布局如上,代码如下)

一块一块分别的导入一堆数据(或组件)

image.png
image.png

第二:Vue和React做了一个创新 数据驱动视图(MVVM setState)

  1. 在上一点中的 前端1.0 甚至是2.0 的时候,因为只是传统的组件化,只是静态渲染,更新还要依赖DOM,所以那个时候jQuery很火!!!
  2. 而 Vue ,React 引入了数据驱动视图的概念后,大大提高了效率。

Vue 2 采用的是 MVVM,React 采用的是 setState

数据驱动视图的概念这里就不过多赘述了。
算了还是一讲:就是我们想改什么数据,不用再去操作DOM,而是直接去Vue 或者React里面改数据就好了,框架会自动的将数据渲染到页面上!也就是因为如此,我们开发的时候,更多的时间可以去关注业务数据和业务逻辑!

第三:然后再开始将 MVVM 是什么?

画个图,一番解释就满分!

  • 首先M 是Model ,V是View ,VM 是ViewModel
  • 通过中间的 VM层,我们在Model 发生变化的时候立刻执行到View 层
  • 同理,我们在View 层触发的事件的时候,我们也可以通过VM层直接去修改数据

image.png

二、 响应式原理

上题中,有一个问题:

就是当组件的data 的数据一旦改变,立刻就会触发视图的个更新。

下面从3分方面来回答这个问题链接

第一: 核心API-Object.defineProperty

这个方法就是在一个对象上定义一个新的属性,或者改变一个对象现有的属性,并且返回这个对象。里面有两个字段 set,get。顾名思义,set是去设置属性的值,而get就是获取属性的值。

举个栗子:

// 在对象中添加一个属性与存取描述符的示例

var bValue;
var o = {};
Object.defineProperty(o, "b", {
  get : function(){
    console.log('监听正在获取b')
    return bValue;
  },
  set : function(newValue){
    console.log('监听正在设置b')
    bValue = newValue;
  },
  enumerable : true,
  configurable : true
});

o.b = 38;
console.log(o.b)
 

最终打印

监听正在设置b
监听正在获取b
38
 

从在上述栗子中,可以看到当我们对 o.b 赋值38的时候,就会调用set函数,这时候给bValue赋值,之后我们就可以通过o.b来获取这个值,这时候,get函数被调用。

第二: 如何实现响应式,代码演示

① 监听对象(深度)

如果只是监听第一层级的属性(比如下面data 里面的name 和 age )很容易就实现了,

但是如果属性是一个对象呢(比如data 里面的 info),这时候怎么监听info.address呢?能不能判断一下是不是对象呢?

图二中 observer()函数就是干这个事的。如果传入这个函数的target(代表要被监听元素)是一个对象,那他就return这个对象的属性,

就像他发现图一的info 是一个对象,那么返回的就是 address 这个对象或者属性!!!

图三中object defineReactive(target,key,value)这个函数传入的这个target 就只是我们监听的这个对象,而不是这个对象的内层属性。

这时候就需要我们在 这个函数里面进行判断,如果传入不是对象或者数组,就返回他本身,那么就返回他所指向的内容。

就像传入的是 图一中 data里面的 name属性,那么返回的就是name 属性

如果传入的是 data里面的info 这个对象,那么就便利这个对象,找到他的所有的属性,然后就找到了adress ,然后再去对他进行这样一个检查,最终得到所有的属性。

image.png
image.png

image.png

② 监听数组

data(){
nums:[10,20,30]
}
 

监听数组我们按照上面监听对象的方式尝试,发现并不能成功!

这里我们需要 去重新定义数组的原型:我这里就大致的解释一番!
image.png
image.png

第三: Object.defineProperty的一些缺点(Vue3.O启用Proxy)这个了解一下就好了

  1. 深度监听,需要递归到底,一次性计算量大

如果data里面的info 是一个层级很省的对象的时候,那我们岂不是要一直递归(上文中的observe方法)

image.png

  1. 无法监听新增属性/删除属性(Vue.set Vue.delete)
  2. 无法原生监听数组,需要特殊处理(需要修改数组原型)

第四: Proxy兼容性问题

  • Proxy兼容性不好,且无法polyfill(IE11,很多安卓浏览器的内核都不支持)
  • Vue2.x还会存在一段时间,所以导学
  • Vue3.O相关知识,下一章讲,这里只是先提一下

三、虚拟DOM(Virtual DOM )和diff

第一:背景了解

  1. DOM 操作非常耗费性能,耗时
  2. 相对来说js 的执行是比较快的,在用框架之前,是用jQuery的可以自行去控制DOM操作的时机手动调整
  3. Vue React 是数据驱动视图,如何有效控制DOM操作?

他们采用虚拟DOM

  1. 虚拟DOM是React提出来的,提出之后的几年里得到了大量的普及,像Vue 从2.0 之后就用了虚拟DOM
  2. 用控制变量的方法,业务复杂度+执行速度=DOM操作最终速度
  3. 业务复杂度这个我们根本就没发控制,需求那么多,哪个保留哪个删去都不合适?
  4. 那我们能不能提高DOM操作的执行速度呢?
  5. 我们把更多的计算转移为JS计算,JS的计算快啊(特别是Chrome的V8引擎发布之后),和DOM速度就不是一个数量级的!

那虚拟DOM是咋做的呢?

第二:虚拟DOM的原理


它先用JS来模拟DOM结构,然后去进行一系列的计算,计算出最小的变更,然后再去操作DOM(这样就最大程度上避免一些无用功的操作),这就虚拟DOM的原理!

第三:原理整明白了,到你咋做的呢?

1. 用JS模拟DOM结构 (暂时整一个 JS模仿的DOM结构:左侧DOM结构,右侧JS的DOM结构)

大厂很可能会要求: 可以把以下DOM机构用JS表示以下吗?仅供参考,其实表达方式因人而异
image.png

2.Vue,React参考snabbdom ,通过snabbdom 学习 虚拟DOM

虚拟DOM用到了diff算法,首先来简单了解一下diff算法

  1. 同样diff算法也不是虚拟DOM独创的,
  2. diff即对比的意思,是一个广泛的概念,比如linux的diff命令,git diff 等等
  3. 两个js 对象也可以做diff,引入一个GitHub的 jiff库
  4. 两棵树可做diff,ru 虚拟DOM的diff ,就是DOM树和JS树做对比

image.png
两棵树的diff 的时间吗复杂度是 O(n^3)

  1. 遍历 treel
  2. 遍历tree2
  3. 排序

1000个节点,要计算1亿次啊,算法不可用

chrome-capture (1).gif

React 大牛想:这不行啊,然后把树的diff 的时间复杂度优化到了O(n)

  1. 只比较同一层级,不跨级比较
  2. tag不相同,则直接删掉重建不再深度比较
  3. tag和key,两者都相同,则认为是相同节点,不再深度比较

image.png

四、 组件渲染和更新过程

面试官不会直接问什么是模板边缘,但是会通过“组件渲染和更新过程”考察?

  1. Vue template complier 将模板编译为 render 函数
  2. 执行render函数生产vnodevnode 其实是 虚拟DOM源码中的一个重要关键词,理解为虚拟DOM的总节点)

① 前置知识:with语法 (只需要了解就好)

  1. 正常我们访问一个对象的某一个属性
console.log(obj.a)
 
  1. 但是使用with 语法
with(obj){
console.log(a)  
}
 

两种方式结果是一样的,只是当我们在用with 语法的时候,需要传入这个对象,然后在{}就可以直接使用它的 某一个属性

② Vue template 为什么要编译呢?

因为我们在 <template> 标签里面写的内容,其实并不是html,而是Vue定义的一种格式。

你想想。正常html 里面可以写 指令,插值,js表达式吗,能实现判断和循环吗?

但是JS可以呀,由此,Vue的模板一定转换为某种JS代码,即使编译模板!

image.png

③ 组件 渲染/更新 过程

初次渲染过程

  1. 解析模板为 render函数(在开发环境或者在浏览器完成,vue-loader)
  2. 触发响应式,监听data属性 getter setter
  3. 执行render函数,生产vnode,patch(elem,vnode)

更新过程

  1. 修改data,触发setter(判断此前在getter中已经被监听)
  2. 重新执行render 函数,生成newVnode
  3. patch(vnode,newVnode),path的diff算法会帮我算出这个新旧DOM节点的最小差异

五、 渲染过程

整个流程介绍

image.png

  1. 黄色区域是我们的render函数,这个时候模板已经编译完成了(Vue template里面的 => render函数)
  2. render 函数生产了虚拟DOM的树(绿色的树),同时render函数会 Touch(触发)Data(紫色区域的getter);
  3. 触发的时候同时也会收集依赖(就我在模板里面触发了哪个变量的getter,我就会把哪个变量Watch(蓝色区域)起来)
  4. 然后我们再去setter的时候,先进行Notify 的判断,判断setter的这个变量是不是我们曾经收集过依赖的那些值,如果是就去通知那些我们收集的依赖,然后再去触发 trigger re-render(重新渲染)

异步渲染

  • ① 首先回顾一下 $nextTick和Vue渲染的方式
  • 汇总data的修改,然后一次性更新视图,减少DOM操作次数,提高性能

image.png

6. 前端路由

前端路由的原理,这里讲的不是具体哪一个框架的路由原理,而是通用的前端路由原理。

Vue-router :
2种模式,h5 historyhash模式

hash 模式特点

通过 window.onhashchange事件
(代码展示) 点击按钮,用js 去改变url值
image.png

image.png
image.png

  1. hash变化会触发网页跳转,即浏览器的前进、后退
  2. hash变化不会刷新页面,SPA必需的特点
  3. hash永远不会提交到server端(自生自灭)

H5 history 模式特点

(代码展示) history.pushState和window.onpopstate
image.png
总结:

  • hash模式window.onhashchange
  • H5 history模式history.pushState和window.onpopstate

Vue原理总结

大厂面试必考原理:所以我觉得需要把所有原理的重点讲清楚,然后热门技术挖一挖深度!
image.png

首先Vue原理的三大块是:响应式虚拟DOM模板编译

  1. 渲染过程 是对以上三个的总结
  2. 组件化 是对Vue整个的事件理念的一个通讲
  3. 前端路由 是对Vue router 的一个讲解

由于本人水平有限,如有描述不准确的地方请给我留言,欢迎交流~

Vue 原理(大厂必考!!!)

原创文章,作者:我心飞翔,如若转载,请注明出处:https://www.pipipi.net/12596.html

发表评论

登录后才能评论