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 的核心,使用数据劫持实现数据驱动视图.在面试中是经常考查的知识点,也是面试加分项. 本文将会循序渐进的解析响应式原理的工作流程,主要以下面结构进行: 分析主要成员,了解它 ...
随机推荐
- 配置Maven环境变量-Eclipse/Idea添加Maven
1. 文件下载 官网下载地址:http://maven.apache.org/download.cgi 下方有我提供的下载链接. 由于下载缓慢,提供一份我的下载链接:https://www.lanzo ...
- zzulioj - 2617 体检
题目链接: http://acm.zzuli.edu.cn/problem.php?id=2617 题目描述: VX玩了这么多游戏以后,感觉自己身体素质和智商都有所下降,所以决定去医院体检一下.已知V ...
- CF Educational Round 78 (Div2)题解报告A~E
CF Educational Round 78 (Div2)题解报告A~E A:Two Rival Students 依题意模拟即可 #include<bits/stdc++.h> us ...
- idea启动java项目,使用调试会占用更多内存
idea启动java项目,使用调试会占用更多内存
- vue中异步请求渲染问题(swiper不轮播)(在开发过程中遇到过什么问题、踩过的坑)
问题描述: 用vue封装一个swiper组件的时候,发现轮播图不能轮播了. 原因: 异步请求的时间远大于生命周期执行的时间,mounted初始化DOM时数据未返回,渲染数据是空数组,导致轮播图的容器层 ...
- 洛谷 P2253 好一个一中腰鼓! 题解
P2253 好一个一中腰鼓! 题目背景 话说我大一中的运动会就要来了,据本班同学剧透(其实早就知道了),我萌萌的初二年将要表演腰鼓[喷],这个无厘头的题目便由此而来. Ivan乱入:"忽一人 ...
- Codeforces Round 563 (Div. 2) 题解
自己开了场镜像玩. 前三题大水题.D有点意思.E完全不会.F被题意杀了……然而还是不会. 不过看过(且看懂)了官方题解,所以这里是六题题解齐全的. A 水题.给原序列排序,如果此时合法则直接输出,否则 ...
- [GXOI/GZOI2019]与或和(位运算,单调栈)
题目链接懒得放了. 题目大意懒得写了. 省选原题哪有找不到的…… 说实话,其实这题是个大水题,被我十秒钟内口胡出来了. 首先位运算除了拆位还能干啥?以下以与为例,或是差不多的. 我们考虑有多少个子矩阵 ...
- HTML基础知识---文本编辑练习
飘柔兰花去油洗发水液露去屑止痒控油 阿道夫净屑舒爽清洁头皮去屑洗发水520ml ...
- 2019-2020-1 20181218《Linux内核原理与分析》第一周作业
目录 问题和参考 有趣/有用的Linux命令 小作业和解答 一些图片 相关学习 本文是学习Linux基础入门(新版)后的总结. 问题和参考 虚拟机莫名崩溃,一天重启了几十次电脑,重装两次系统,心累.想 ...