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 的核心,使用数据劫持实现数据驱动视图.在面试中是经常考查的知识点,也是面试加分项. 本文将会循序渐进的解析响应式原理的工作流程,主要以下面结构进行: 分析主要成员,了解它 ...
随机推荐
- [SDOI2018]物理实验 set,扫描线,旋转坐标系
[SDOI2018]物理实验 set,扫描线,旋转坐标系 链接 loj 思路 先将导轨移到原点,然后旋转坐标系,参考博客. 然后分线段,每段的贡献(三角函数值)求出来,用自己喜欢的平衡树,我选set. ...
- 洛谷 p1516 青蛙的约会 题解
dalao们真是太强了,吊打我无名蒟蒻 我连题解都看不懂,在此篇题解中,我尽量用语言描述,不用公式推导(dalao喜欢看公式的话绕道,这篇题解留给像我一样弱的) 进入正题 如果不会扩展欧里几德的话请先 ...
- P1553 数字反转(升级版)
Emma,关于这道题,我..不想说啥子,也就做了它一个下午左右吧(原由:本人太菜) 补充一个知识点goto语句: 这个东西特别的好用,可以直接无条件调到冒号后面的语句,进行操作. 举个例子: #inc ...
- 【树状数组】【P5069】[Ynoi2015]纵使日薄西山
Description 给定一个长度为 \(n\) 的非负整数序列 \(\{a_n\}\),\(q\) 次操作,每次要么单点修改序列某个值,要么查询整个序列需要操作多少次才能变成全 \(0\). 一次 ...
- C语言实现聊天室软件
/* common.h */ /*服务器端口信息*/ #define PORTLINK ".charport" /*缓存限制*/ #define MAXNAMELEN 256 #d ...
- js 校验手机号码格式
手机号码格式简单校验 原理:判断手机号是否以已经发行的手机号码段开头,而且判断其余9位是否是数字. 方式一: var phone = $('#phone').val(); var regex = ...
- 【Gamma】PhyLab 测试报告
PhyLab Gamma测试报告 测试中发现的bug Gamma阶段新Bug Bug 可能原因 部分错误码设置与原先抛异常的逻辑冲突 原先代码中使用了一些特殊的办法处理异常 Beta未发现Bug Bu ...
- STL源码剖析 阅读笔记
结构图:
- CentOS安装Hive
1.环境和软件准备: hive版本:apache-hive-2.3.6-bin.tar.gz,下载地址:https://mirrors.tuna.tsinghua.edu.cn/apache/hive ...
- 那些陌生的C++关键字
C/C++中的关键字如下: 下面我们主要介绍一些比较陌生的关键字,一些常见的关键字这里就不再赘述了. 1.asm asm 是一个语句的分隔符,不能单独出现,必须接汇编指令.一组被大括号包含的指令或一对 ...