vue响应式原理,去掉优化,只看核心
Vue响应式原理
作为写业务的码农,几乎不必知道原理。但是当你去找工作的时候,可是需要造原子弹的,什么都得知道一些才行。所以找工作之前可以先复习下,只要是关于vue的,必定会问响应式原理。
核心:
//es5
Object.defineProperty(obj,key,{
get() {
// 获取obj[key]的时候触发
},
set(val) {
// obj[key] = 'xxx'时触发
}
})
其实,只需要在修改data值的时候,需要触发一个回调方法,来更新与此值有关的数据,就完了。但是你面试的时候,那些大佬可不会觉得是这样的,需要把整个流程说明白才行。
简单的Vue响应式代码如下:
Vue.js:
class Vue {
constructor(opts) {
this.opts = opts
if (opts.data) this.initData(opts.data);
if (opts.watch) this.initWatch(opts.watch);
if (opts.computed) this.initComputed(opts.computed);
if (opts.el) this.$mount(opts.el)
}
initData(data) {
// 让data上的数据被get的时候能够搜集watcher,data变为观察者
new Observable(data);
this.data = data
// 数据可在this上直接读取
Object.keys(data).forEach(key => {
this.proxy(key)
})
}
initWatch(watch) {
Object.keys(watch).forEach(key => {
//
new Watcher(this, key, watch[key])
})
}
initComputed(data) {
Object.keys(data).forEach(key => {
new Watcher(this, key)
this.proxy(key, {
get: data[key],
})
})
}
$mount(el) {
el = document.querySelector(el)
this.template = el.innerHTML
this.el = el
const fn = _ => {
const nwTemp = this.parseHTML(this.template)
this.el.innerHTML = nwTemp
if(this.opts.mounted) {
this.opts.mounted.call(this)
}
}
new Watcher(this, fn)
}
parseHTML(template) {
return template.replace(/\{\{(.*?)\}\}/g, (str, str1) => {
return this[str1.trim()]
})
}
// 将数据直接挂到this上,使用getterSetter代理,获取vm.data上的值
proxy(key, getterSetter) {
const vm = this
getterSetter = getterSetter || {
set(value) {
vm.data[key] = value
},
get() {
return vm.data[key]
}
}
Object.defineProperty(vm, key, getterSetter)
}
}
// 给data作为观察者用的
class Observable {
constructor(obj) {
Object.keys(obj).forEach(key => {
this.defineReact(obj, key, obj[key])
});
}
defineReact(obj, key, value) {
const dep = new Dep()
Object.defineProperty(obj, key, {
get() {
// 获取data里面信息的时候,能够搜集依赖,这些依赖都是watcher实例
if (Dep.target) {
dep.append(Dep.target)
}
return value
},
set(val) {
value = val
// 修改data里面数据的时候,去通知已搜集的依赖更新
dep.notify()
}
})
}
}
// 搜集与触发wacher
class Dep {
constructor() {
this.subs = []
}
append(watcher) {
// 避免重复添加watcher
// watcher 在update的时候,会重新获取值,此时不必再添加
if(this.subs.includes(watcher)) return
this.subs.push(watcher)
}
notify() {
this.subs.forEach(watcher => {
watcher.update()
})
}
}
Dep.target = null
class Watcher {
// keyOrFn 为字符串或者function,opts.watch为字符串,computed,$mount中为function
constructor(vm, keyOrFn, cb) {
this.cb = cb
if (typeof keyOrFn === 'string') {
this.getter = function () {
return vm[keyOrFn] // 例:initWatch时,watch:{a(){}} ,a为data里的数据,此处获取vm.a会触发a的收集
}
} else {
this.getter = keyOrFn // 如果为fn(computed中)值为此函数的返回值
}
this.value = this.get()
}
get() {
Dep.target = this // 此watcher记录下来
const value = this.getter(this.vm)
// 运行getter,如果是watch,获取一次data里的值,完成收集。
// 如果是computed,运行其方法,其方法中含有data的值时,会触发收集
// 当更新时,也会触发getter
Dep.target = null
return value
}
update() {
// 更新
const oldValue = this.value
// 重新获取值
this.value = this.get()
if (this.cb) {
//如果是watch,会触发watch的函数
this.cb.call(this.vm, this.value, oldValue)
}
}
}
index.html
<div id="app">
<h2>Vue响应式原理</h2>
<br />
msg: {{ msg }}
<br />
<p>num: {{ num }}</p>
<p>num+1计算属性值:{{ add1 }}</p>
<button>add</button>
</div>
<script src="./Vue.js"></script>
<script>
const app = new Vue({
el: "#app",
data: {
msg: "这是msg",
num: 1
},
watch: {
msg(newVal, oldVal) {
console.log(newVal, oldVal);
}
},
computed: {
add1() {
return this.num + 1;
}
},
mounted() {
const btn = document.querySelector("button");
btn.onclick = _ => {
this.num += 1;
};
}
});
</script>
总结
1. 需要this.xxx 访问的做proxy
2. data做 Observer 动态数据化处理。
3. data每一个属性都new Dep 管理此属性的订阅及改变数据后的发布。
4. computed、watch各属性及$mount 做 new Watch订阅。
vue响应式原理,去掉优化,只看核心的更多相关文章
- 深度解析 Vue 响应式原理
深度解析 Vue 响应式原理 该文章内容节选自团队的开源项目 InterviewMap.项目目前内容包含了 JS.网络.浏览器相关.性能优化.安全.框架.Git.数据结构.算法等内容,无论是基础还是进 ...
- 详解Vue响应式原理
摘要: 搞懂Vue响应式原理! 作者:浪里行舟 原文:深入浅出Vue响应式原理 Fundebug经授权转载,版权归原作者所有. 前言 Vue 最独特的特性之一,是其非侵入性的响应式系统.数据模型仅仅是 ...
- Vue源码--解读vue响应式原理
原文链接:https://geniuspeng.github.io/2018/01/05/vue-reactivity/ Vue的官方说明里有深入响应式原理这一节.在此官方也提到过: 当你把一个普通的 ...
- 深入Vue响应式原理
深入Vue.js响应式原理 一.创建一个Vue应用 new Vue({ data() { return { name: 'yjh', }; }, router, store, render: h =& ...
- vue响应式原理解析
# Vue响应式原理解析 首先定义了四个核心的js文件 - 1. observer.js 观察者函数,用来设置data的get和set函数,并且把watcher存放在dep中 - 2. watcher ...
- 浅析Vue响应式原理(三)
Vue响应式原理之defineReactive defineReactive 不论如何,最终响应式数据都要通过defineReactive来实现,实际要借助ES5新增的Object.definePro ...
- 深入解析vue响应式原理
摘要:本文主要通过结合vue官方文档及源码,对vue响应式原理进行深入分析. 1.定义 作为vue最独特的特性,响应式可以说是vue的灵魂了,表面上看就是数据发生变化后,对应的界面会重新渲染,那么响应 ...
- 浅谈vue响应式原理及发布订阅模式和观察者模式
一.Vue响应式原理 首先要了解几个概念: 数据响应式:数据模型仅仅是普通的Javascript对象,而我们修改数据时,视图会进行更新,避免了繁琐的DOM操作,提高开发效率. 双向绑定:数据改变,视图 ...
- 手摸手带你理解Vue响应式原理
前言 响应式原理作为 Vue 的核心,使用数据劫持实现数据驱动视图.在面试中是经常考查的知识点,也是面试加分项. 本文将会循序渐进的解析响应式原理的工作流程,主要以下面结构进行: 分析主要成员,了解它 ...
随机推荐
- Pandas | 10 排序
Pandas有两种排序方式,它们分别是 - 按标签 按实际值 import pandas as pd import numpy as np df=pd.DataFrame(np.random.rand ...
- 【BZOJ3711】Druzyny
[BZOJ3711]Druzyny 题面 bzoj 题解 首先我们有一个\(O(n^2)\)的\(dp\): 设\(f_i\)表示现在已经分好了\(1...i\)的组,且\(i\)作为一组的结尾的最大 ...
- 为什么需要动态SQL
为什么需要动态SQL 在使用EF或者写SQL语句时,查询条件往往是这样一种非常常见的逻辑:如果客户填了查询信息,则查询该条件:如果客户没填,则返回所有数据. 我常常看到很多人解决这类问题时使用了错误的 ...
- pom.xml文件引入tools.jar
最近做hbase开发时,引入相关jar包后,出现了以下错误 Missing artifact jdk.tools:jdk.tools:jar:1.8 绝对地址引用 <dependency> ...
- Shell脚本之七 选择、循环结构
一.if else if 语法格式 if condition then command1 command2 ... commandN fi 写成一行(适用于终端命令提示符): if [ $(ps -e ...
- python 统计字符串中指定字符出现次数的方法
python 统计字符串中指定字符出现次数的方法: strs = "They look good and stick good!" count_set = ['look','goo ...
- StringTable
首先看这样一个面试题 // StringTable [ "a", "b" ,"ab" ] hashtable 结构,不能扩容 public ...
- python入门之函数的嵌套
目录 函数的嵌套调用 函数的嵌套定义 函数的嵌套调用 在函数内调用函数 def index(): print('from index') def func(): index() print('from ...
- linux下安装谷歌拼音输入法
linux下安装谷歌拼音输入法 输入以下命令,等待安装完成. sudo apt-get install fcitx 接着输入,完成安装谷歌中文输入法 sudo apt-get install fcit ...
- 蚂蚁花呗5面面试真题,你敢来挑战一下吗?(Java岗)
蚂蚁花呗一面(一个小时): JDK 中有哪几个线程池?顺带把线程池讲了个遍 Java容器有哪些?哪些是同步容器,哪些是并发容器? ArrayList和LinkedList的插入和访问的时间复杂度? j ...