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 的核心,使用数据劫持实现数据驱动视图.在面试中是经常考查的知识点,也是面试加分项. 本文将会循序渐进的解析响应式原理的工作流程,主要以下面结构进行: 分析主要成员,了解它 ...
随机推荐
- 学习-guava
Guava Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库 例如:集合 [collections] .缓存 [caching] .原生类型支持 [primitives sup ...
- python基础_格式化输出(%用法和format用法)(转载)
python基础_格式化输出(%用法和format用法) 目录 %用法 format用法 %用法 1.整数的输出 %o -- oct 八进制%d -- dec 十进制%x -- hex 十六进制 &g ...
- luoguP2039 [AHOI2009]跳棋 巧妙的dp
设\(f[i]\)表示在第\(i\)个格子上弄一个棋子的最小代价,前后扫两遍dp后统计答案即可. 代码 #include<bits/stdc++.h> using namespace st ...
- django数据处理
目录 django积累 连接数据库: 模板 后台管理 功能扩展: 日志打印: django积累 连接数据库: 连接数据库 : 1.创建数据库 create database oa default ch ...
- 几句话总结一个算法之DQN
DQN利用深度学习对Q-learning的一个扩展,回顾上篇文章,Q-learning的核心在于Q(s,a)的建模.如果状态s非常复杂,很难通过一张表来存储所有的状态. 深度学习正好可以自动提取s的特 ...
- Docker 部署web项目
1.查找Docker Hub上的tomcat镜像 # docker search tomcat 2.拉取官方的镜像 # docker pull tomcat 提示:Using default ...
- Struts2利用iText导出word文档(包含表格)以提供下载
J2EE ExcelStrutsXML 在公司实习期间,带我的老师让我实现一功能——在显示课表的页面上上点击“导出文件“时能以word文档形式下载课表.将课表导出到excel里的功能他们已经实现了, ...
- idea导入工程
idea导入svn中的工程,一般是多模块的工程. 1 在idea中导入一个工程的目录,可以建立对应的文件夹 dy-task ,svn选择对应的分支导入 2 在dy-task同目录下建立其他目录 dy- ...
- unity内存管理(转)
转自:https://www.cnblogs.com/zsb517/p/5724908.html Unity3D 里有两种动态加载机制:一个是Resources.Load,另外一个通过AssetBun ...
- Linux命令中service的用法
用途说明 service命令用于对系统服务进行管理,比如启动(start).停止(stop).重启(restart).查看状态(status)等.相关的命令还包括chkconfig.ntsysv等,c ...