1 MVVM
涉及面试题:什么是
MVVM
?比之MVC
有什么区别?
首先先来说下 View 和 Model
-
View
很简单,就是用户看到的视图 -
Model
同样很简单,一般就是本地数据和数据库中的数据
基本上,我们写的产品就是通过接口从数据库中读取数据,然后将数据经过处理展现到用户看到的视图上。当然我们还可以从视图上读取用户的输入,然后又将用户的输入通过接口写入到数据库中。但是,如何将数据展示到视图上,然后又如何将用户的输入写入到数据中,不同的人就产生了不同的看法,从此出现了很多种架构设计。
传统的
MVC
架构通常是使用控制器更新模型,视图从模型中获取数据去渲染。当用户有输入时,会通过控制器去更新模型,并且通知视图进行更新
-
但是 MVC
有一个巨大的缺陷就是控制器承担的责任太大了,随着项目愈加复杂,控制器中的代码会越来越臃肿,导致出现不利于维护的情况。 -
在 MVVM
架构中,引入了ViewModel
的概念。ViewModel
只关心数据和业务的处理,不关心View
如何处理数据,在这种情况下,View
和Model
都可以独立出来,任何一方改变了也不一定需要改变另一方,并且可以将一些可复用的逻辑放在一个ViewModel
中,让多个View
复用这个ViewModel
。
-
以 Vue
框架来举例,ViewModel
就是组件的实例。View
就是模板,Model
的话在引入Vuex
的情况下是完全可以和组件分离的。 -
除了以上三个部分,其实在 MVVM
中还引入了一个隐式的Binder
层,实现了View
和ViewModel
的绑定
-
同样以 Vue
框架来举例,这个隐式的Binder
层就是Vue
通过解析模板中的插值和指令从而实现View
与ViewModel
的绑定。 -
对于 MVVM
来说,其实最重要的并不是通过双向绑定或者其他的方式将View
与ViewModel
绑定起来,而是通过ViewModel
将视图中的状态和用户的行为分离出一个抽象,这才是MVVM
的精髓
2 Virtual DOM
涉及面试题:什么是
Virtual DOM
?为什么Virtual DOM
比原生DOM
快?
-
大家都知道操作 DOM
是很慢的,为什么慢的原因以及在「浏览器渲染原理」章节中说过,这里就不再赘述了- 那么相较于DOM
来说,操作JS
对象会快很多,并且我们也可以通过JS
来模拟DOM
const ul = {
tag: 'ul',
props: {
class: 'list'
},
children: {
tag: 'li',
children: '1'
}
}
上述代码对应的 DOM
就是
<ul class='list'>
<li>1</li>
</ul>
-
那么既然 DOM
可以通过JS
对象来模拟,反之也可以通过JS
对象来渲染出对应的DOM
。当然了,通过JS
来模拟DOM
并且渲染对应的DOM
只是第一步,难点在于如何判断新旧两个JS
对象的最小差异并且实现局部更新DOM
首先
DOM
是一个多叉树的结构,如果需要完整的对比两颗树的差异,那么需要的时间复杂度会是O(n ^ 3)
,这个复杂度肯定是不能接受的。于是React
团队优化了算法,实现了O(n)
的复杂度来对比差异。 实现O(n)
复杂度的关键就是只对比同层的节点,而不是跨层对比,这也是考虑到在实际业务中很少会去跨层的移动DOM
元素。 所以判断差异的算法就分为了两步
-
首先从上至下,从左往右遍历对象,也就是树的深度遍历,这一步中会给每个节点添加索引,便于最后渲染差异 -
一旦节点有子元素,就去判断子元素是否有不同
在第一步算法中我们需要判断新旧节点的
tagName
是否相同,如果不相同的话就代表节点被替换了。如果没有更改tagName
的话,就需要判断是否有子元素,有的话就进行第二步算法。
在第二步算法中,我们需要判断原本的列表中是否有节点被移除,在新的列表中需要判断是否有新的节点加入,还需要判断节点是否有移动。
举个例子来说,假设页面中只有一个列表,我们对列表中的元素进行了变更
// 假设这里模拟一个 ul,其中包含了 5 个 li
[1, 2, 3, 4, 5]
// 这里替换上面的 li
[1, 2, 5, 4]
从上述例子中,我们一眼就可以看出先前的
ul
中的第三个li
被移除了,四五替换了位置。
那么在实际的算法中,我们如何去识别改动的是哪个节点呢?这就引入了
key
这个属性,想必大家在Vue
或者React
的列表中都用过这个属性。这个属性是用来给每一个节点打标志的,用于判断是否是同一个节点。
-
当然在判断以上差异的过程中,我们还需要判断节点的属性是否有变化等等。 -
当我们判断出以上的差异后,就可以把这些差异记录下来。当对比完两棵树以后,就可以通过差异去局部更新 DOM
,实现性能的最优化。
当然了
Virtual DOM
提高性能是其中一个优势,其实最大的优势还是在于:
-
将 Virtual DOM
作为一个兼容层,让我们还能对接非Web
端的系统,实现跨端开发。 -
同样的,通过 Virtual DOM
我们可以渲染到其他的平台,比如实现SSR
、同构渲染等等。 -
实现组件的高度抽象化
3 路由原理
涉及面试题:前端路由原理?两种实现方式有什么区别?
前端路由实现起来其实很简单,本质就是监听
URL
的变化,然后匹配路由规则,显示相应的页面,并且无须刷新页面。目前前端使用的路由就只有两种实现方式
-
Hash
模式 -
History
模式
1. Hash 模式
www.test.com/#/` 就是 `Hash URL`,当 `#` 后面的哈希值发生变化时,可以通过 `hashchange` 事件来监听到 `URL` 的变化,从而进行跳转页面,并且无论哈希值如何变化,服务端接收到的 `URL` 请求永远是 `www.test.com
window.addEventListener('hashchange', () => {
// ... 具体逻辑
})
Hash
模式相对来说更简单,并且兼容性也更好
2. History 模式
History` 模式是 `HTML5` 新推出的功能,主要使用 `history.pushState` 和 `history.replaceState` 改变 `URL
-
通过 History
模式改变URL
同样不会引起页面的刷新,只会更新浏览器的历史记录。
// 新增历史记录
history.pushState(stateObject, title, URL)
// 替换当前历史记录
history.replaceState(stateObject, title, URL)
当用户做出浏览器动作时,比如点击后退按钮时会触发
popState
事件
window.addEventListener('popstate', e => {
// e.state 就是 pushState(stateObject) 中的 stateObject
console.log(e.state)
})
两种模式对比
-
Hash
模式只可以更改#
后面的内容,History
模式可以通过API
设置任意的同源URL
-
History
模式可以通过API
添加任意类型的数据到历史记录中,Hash
模式只能更改哈希值,也就是字符串 -
Hash
模式无需后端配置,并且兼容性好。History
模式在用户手动输入地址或者刷新页面的时候会发起URL
请求,后端需要配置index.html
页面用于匹配不到静态资源的时候
4 Vue 和 React 之间的区别
-
Vue
的表单可以使用v-model
支持双向绑定,相比于React
来说开发上更加方便,当然了v-model
其实就是个语法糖,本质上和React
写表单的方式没什么区别 -
改变数据方式不同, Vue
修改状态相比来说要简单许多,React
需要使用setState
来改变状态,并且使用这个API
也有一些坑点。并且Vue
的底层使用了依赖追踪,页面更新渲染已经是最优的了,但是React
还是需要用户手动去优化这方面的问题。 -
React 16
以后,有些钩子函数会执行多次,这是因为引入Fiber
的原因 -
React
需要使用JSX
,有一定的上手成本,并且需要一整套的工具链支持,但是完全可以通过JS
来控制页面,更加的灵活。Vue
使用了模板语法,相比于JSX
来说没有那么灵活,但是完全可以脱离工具链,通过直接编写render
函数就能在浏览器中运行。 -
在生态上来说,两者其实没多大的差距,当然 React
的用户是远远高于Vue
的
原文始发于微信公众号(消失的程序员):MVVM/虚拟DOM/前端路由
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/250670.html