mvvm和mvc的区别:
view 是视图层,
model是数据层,比如本地数据和存储于数据库的数据
当view和model需要交互的时候,就衍生出很多种架构设计。传统的mvc模式,增加了controller层,通过控制器更新视图,视图从模型中获取数据去渲染,当处理例如用户输入的时候,通知控制器去更新模型层,并且更新视图,但是这会导致控制层相当臃肿,不利于维护。
而mvvm增加了viewmodel层,是视图和模型层完全分离,vm中只有数据处理和业务处理,功能分工清晰,并且多个vm可以复用,例如vue,组件实例就可以看成vm。对于mvvm,最重要不是双向数据绑定,而是vm层将视图的状态和用户行为的抽离和抽象。
2. diff的算法
diff算法的优化在于他是同级对比,将复杂度控制在了o(n),diff的总体步骤分为两步
第一,从上往下从左往右进行遍历对象,如果有子元素就深度遍历,并且会给每个对象增加索引,便于最后渲染差异
第二,对比差异。
通过key + name + tagname来判断是不是同一个节点,
如果新的节点有进行新增,如果新的节点没有进行删除,
对比完成之后,就可以根据差异局部更新dom。
virtual dom
是用js对象来模拟dom对象,是一个多叉树的结构。它实现了跨平台的兼容,而且组件高度抽象化。
前端路由原理
监听url的变化,根据路由的配置,调用相应的组件。history需要后端配置,hash模式相对简单。
history模式:更新浏览器的历史记录
history.pushState(obj, title, url)
history.replaceState(obj, title, url)
window.addEventListener('popstate', function() {
console.log(e.state)
})
hash模式:监听hashChange
window.addEventListener('hashChange', function() {})
vue 和react的不同
1.vue的v-model语法糖可以双向绑定,而react需要自己调用setState,并且vue的响应式数据更新视图已经做了性能优化,不需要用户去过多干预,而react还需要用户手动优化
2.react引入了jsx语法,可以完全用js调用页面,更加灵活。而vue也可以通过插件来支持jsx。
vue的生命周期
-
BeforeCreate:获取不到props和data,这个周期之后才initState
-
created: 可以获取props和data,这时候一般进行页面初始化操作,例如请求或者设置默认值等
-
beforeMount:获取不到refs
-
mounted:渲染完毕
-
beforeUpdate 和 updated
-
keep-alive的生命周期:activated和deactivated,
组件切换的时候不会进行销毁,而是缓存到内存中,执行deactivated。
命中缓存渲染后,执行activated。
递归挂载:
父 beforeCreated -> 子 beforeCteated, 子created -> 父created -> 子mounted -> 父mounted
react的生命周期
-
如果一个很复杂的组件,改变了最上层的state,调用栈会很长,所以引入了fibber机制:将同步渲染改为异步渲染,分段计算更新。
-
异步渲染分两个阶段: Reconciliation 和commit,前者可以打断,所以会调用多次。后者不能暂停
- Reconciliation:
componentWillMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
- commit
componentDidMount
componentDidUpdate
componentWillUnmount
-
新的api,解决调用多次的问题
-
getDerivedStateFromProps替换componentWillReceiveProps
在初始化和update时候被调用
2. getSnapshotBeforeUpdate 替换componentWillUpdate、
在update后dom更新前调用,用于读取最新的数据
组件通信
- 兄弟同级
vue:可以通过eventBus,或者vuex通信
react:通过父组件来管理状态和函数
-
父子
-
vue:props和emit
react:props传递数据和方法,子通过调用父的方法改变数据
-
vue:
children
-
.sync:通过监听@update:val方法改变数据,通过emit('update:val',val)传递改变
-
v-model:监听on-input事件
-
跨级
vue:可以通过inject注入和provide,vuex/eventbus
react: Context API/redux/eventbus
mixins
通过Vue.mixin({
beforeCreate () {
全局事件处理
}
})
组件内部的mixins,如果和组件有相同的属性和事件,会取组件的属性,
如果有相同的生命周期函数,会合并mixins先执行,组件后执行
当然可以通过Vue.config.optionMergeStrategies自定义合并的逻辑
响应式的原理
-
在beforeCreate之后,vue会调用initState函数设置data的响应式
-
首先通过proxy把this.options.data上的数据全部代理到vm上
-
循环调用defineProperty,监听属性的set和get
-
实例化watcher,依赖收集
-
通过dep对象解耦属性依赖添加和派发
-
缺陷
-
不能监听数组下标的变化
-
不能监听到对象新增属性
-
通过重写方法监听数据变化 [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
class Dep {
constructor () {
this.subs = []
}
addSub (sub) {
this.subs.push(sub)
}
notify () {
this.subs.forEach(sub => {
sub.update
})
}
}
Dep.target = null
class Watcher {
constructor (obj, key, cb) {
Dep.target = this // 触发get
this.cb = cb
this.obj = obj
this.key = key
this.value = obj[key]
Dep.target = null // 已经收集了依赖可以清空
}
update () {
this.value = this.obj[this.key]
this.cb(this.value)
}
}
function defineReactive(obj, key, val) {
let dep = new Dep()
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
set (newVal) {
val = newVal
dp.update(val)
},
get () {
if (Dep.target) {
dep.addSub(Dep.target)
}
return val
}
})
}
编译过程
-
实现一个模版语法
-
编译分为三步:
-
模版转化为ast(标签闭合,根组件只有一个,
-
优化ast(静态内容提取,复用vdom,跳过diff)
-
ast转化为render
nextTick
1.默认使用微任务,但优先级高,执行可能冒泡事件更快,所以在v-on的事件上使用宏任务
先检测setImmediate,然后使用messagechange,最后使用setTimeout
setState
setState是异步的,调用之后不会马上引起state的变化,所以多次调用要注意。
react性能优化(v16版本)
React.memo(() => (
<div>
PureComponent
</div>
))
hoc
概念:实现一个函数,传入一个组件,在函数内部在实现一个函数去扩展传入的组件,最后返回新组件
function outer (fn) { // 高阶函数
function inner(val) {
return val
}
return inner
}
react的事件机制
1.合成事件,jsx内部的事件没有绑定到dom上面,而是通过事件代理到了document上面,并且document上面的事件也不是原生事件,而是自己实现的合成事件。所以要取消冒泡应该用event.preventDefault而不是event.stopPropagation
合成事件的好处:
-
跨浏览器兼容
-
原生事件,浏览器会创建事件对象,当事件特别多的时候会有性能和内存的损耗,而合成事件通过维护一个事件池来优化性能
网友评论