Vue2响应式原理
vue2响应式原理
vue的特性:数据驱动视图和双向数据绑定。vue官方文档也提供了响应式原理的解释:
Object.defineProperty()
Object.defineProperty()
的作用是直接在一个对象上定义一个新属性,或者修改一个属性
使用方式:Object.defineProperty(对象名,属性名,配置项)
<script>
let person = {
name: '张三',
sex: '男',
}
Object.defineProperty(person,'age',{
value: 18
}) //不能参与遍历
</script>
上述写法是给person
对象添加一个age
属性,属性的值是18
但是这种写法:
- 不能进行枚举,即无法在遍历的时候获取到
age
属性的值 - 不能被修改
- 不能删除
所以Object.defineProperty()
还有其他配置项
Object.defineProperty(person,'age',{
value: 18
enumerable: true //控制属性是否可以枚举,默认值是false
writeable: true //控制属性是否可以被修改,默认值是false
configurable: true //控制属性是否可以被删除,默认值是false
})
现在有一个需求:定义一个新的变量number
,当number
的值修改后,person
中age
的值也相应被修改;而person
中age
的值被修改后,number
的值也相应被修改。
这个时候需要借助新的配置项get
和set
<script>
let number = 18
let person = {
name: '张三',
sex: '男',
}
//能够实现number的值修改后,person中age的值也相应被修改
Object.defineProperty(person,'age',{
//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
get:function(){
return number
},
//当有人修改person的age属性时,set函数(setter)就会被调用,且接收到修改的具体值
set(value){
number = value
}
})
</script>
数据代理
数据代理就是通过一个对象代理另一个对象中属性的操作
vue
就是通过vm
对象来代理data
对象中属性的操作
<body>
<div id="app">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
</div>
</body>
<script>
const vm = new Vue({
el: '#app',
data: {
name: '张三',
age: 18
}
})
</script>
控制台输出vm
,我们可以看到name
和age
这两个属性
这两个属性都是通过Object.defineProperty()
添加到vm
上,所以可以发现他们都有对应的getter/setter
也就是说:当读取vm
中的name
时,会调用getter
,把data.name
给name
;当修改vm
中的name
时,会调用setter
,修改data.name
中的值(这里跟第一个例子是同一个道理)
但是我们会发现vm
上没有data
(疑惑:明明在创建vue
实例对象的时候,设置了data
,为什么取不到)
其实我们以为的这个data
其实是_data
,可以验证一下:
let data = {
name: '张三',
age: 18
}
const vm = new Vue({
el: '#app',
data
})
控制台进行一下判断:
所以我们获取数据的时候,也可以通过vm._data.age
来获取
vue
为了编码更方便,进行了数据代理,遍历data
中的所有属性,把每个属性都添加到vm
中,指定getter/setter
。
所以可以直接通过vm.age
来获取数据
基本原理:
- 通过
Object.defineProperty()
把data
对象中所有属性添加到vm
上 - 为每一个添加
vm
上的属性,都指定一个getter/setter
- 在
getter/setter
内部去操作(读/写)data
中对应的属性
实现双向绑定
双向绑定就是数据发生变化时,视图也跟着变。核心是数据劫持和发布者-订阅者模式
数据劫持实质就是使用defineProperty
重写getter/setter
。当数据改变时,set
就会劫持这个数据的变化,更新视图(view)
但是由于defineProperty
无法检测到对象和数组内部的变化,所以遇到属性为对象时,会递归观察该属性;遇到数组时,会重写push
、pop
、shift
等方法。
监测对象中的数据
最开始会想认为利用getter/setter
,但是这样会造成死循环。只要有人获取name
的值,就会调用get
,然后又会获取一次person.name
,造成死循环。set
同理。
//错误的代码!!!!!!!!!
let person = {
name: '张三',
}
Object.defineProperty(person, 'name', {
get: function() {
return person.name
},
set(value) {
person.age = name
}
})
正确的做法是:监听数据的每一个属性,当监听到属性值发生变化时,通知订阅者去更新视图,重新进行模板解析。
<script>
let data = {
name: '张三',
}
//创建一个观察者实例对象,用于监视data中属性的变化
const obs = new Observer(data)
//准备一个vm实例对象
let vm = {}
vm._data = data = obs
function Observer(obj) {
//汇总对象中所有的属性形成一个数组
const keys = Object.keys(obj)
//遍历
keys.forEach((k) => {
Object.defineProperty(this, k, {
get() {
return obj[k]
},
set(val) {
obj[k] = val
}
})
})
}
</script>
上述代码只是一个例子,只会对一层对象进行处理,vue
的操作是递归,直到数据类型是简单数据类型。
如需给后添加的属性做响应式,可以使用
Vue.set(object,propertyName,value)
或vm.$set(object,propertyName,value)
data: {
student:{
name: '张三',
age: 18,
friends:[
{name:'小明',age:20},
{name:'李四',age:15}
]
}
}
Vue.set(this.student, 'sex', '男')
this.$set(this.student, 'sex', '男')
监测数组中的数据
这里可以去看一下vue
的官方文档:
通过包裹数组更新元素的方法实现,本质就是做了两件事
(1)调用原生对应的方法对数组进行更新
(2)重新解析模板,进而更新页面
所以在vue
修改数组中的某个元素一定要用如下方法:
- 使用API:
push()
,pop()
,shift()
,splice()
,sort()
,reverse()
等 Vue.set()
,vm.$set()
Vue2响应式原理的更多相关文章
- [切图仔救赎]炒冷饭--在线手撸vue2响应式原理
--图片来源vue2.6正式版本(代号:超时空要塞)发布时,尤雨溪推送配图. 前言 其实这个冷饭我并不想炒,毕竟vue3马上都要出来.我还在这里炒冷饭,那明显就是搞事情. 起因: 作为切图仔搬砖汪,长 ...
- Vue2 响应式原理
我们经常用vue的双向绑定,改变data的某个属性值,vue就马上帮我们自动更新视图,下面我们看看原理. Object的响应式原理: 可以看到,其实核心就是把object的所有属性都加上getter. ...
- vue2响应式原理与vue3响应式原理对比
VUE2.0 核心 对象:通过Object.defineProtytype()对对象的已有属性值的读取和修改进行劫持 数组:通过重写数组更新数组一系列更新元素的方法来实现元素的修改的劫持 Object ...
- 由浅入深,带你用JavaScript实现响应式原理(Vue2、Vue3响应式原理)
由浅入深,带你用JavaScript实现响应式原理 前言 为什么前端框架Vue能够做到响应式?当依赖数据发生变化时,会对页面进行自动更新,其原理还是在于对响应式数据的获取和设置进行了监听,一旦监听到数 ...
- vue3剖析:响应式原理——effect
响应式原理 源码目录:https://github.com/vuejs/vue-next/tree/master/packages/reactivity 模块 ref: reactive: compu ...
- vue2.0与3.0响应式原理机制
vue2.0响应式原理 - defineProperty 这个原理老生常谈了,就是拦截对象,给对象的属性增加set 和 get方法,因为核心是defineProperty所以还需要对数组的方法进行拦截 ...
- Vue2.x响应式原理
一.回顾Vue响应式用法 vue响应式,我们都很熟悉了.当我们修改vue中data对象中的属性时,页面中引用该属性的地方就会发生相应的改变.避免了我们再去操作dom,进行数据绑定. 二.Vue响应 ...
- Vue源码--解读vue响应式原理
原文链接:https://geniuspeng.github.io/2018/01/05/vue-reactivity/ Vue的官方说明里有深入响应式原理这一节.在此官方也提到过: 当你把一个普通的 ...
- Vue响应式原理的实现-面试必问
Vue2的数据响应式原理 1.什么是defineProperty? defineProperty是设置对象属性,利用属性里的set和get实现了响应式双向绑定: 语法:Object.definePro ...
随机推荐
- 内网渗透----Linux下信息收集
基础信息 1.系统类型 cat /etc/issue查看系统名称 Lsb-release查看系统名称.版本号 2. 内核版本 uname –a 查看所有信息 ls /root |grep vmlinu ...
- 如何批量修改图片名称(win下)
深度学习目标检测任务中常常需要大量的图片,这些图片一般来自网络爬虫或是自行批量下载,但下载下的图片常常在保存时被命名为长段英文数字混写,因此规律化命名下载的图片数据名称就显得尤为重要了,下面我演示在本 ...
- Spring核心思想:IOC(控制反转)、DI(依赖注入)和AOP(面向切面编程)
Spring有三大核心思想,分别是控制反转(IOC,Inversion Of Controller),依赖注入(DI,Dependency Injection)和面向切面编程(AOP,Aspect O ...
- thrift使用和源码分析
1 前言 thrift的官方文档比较差,很多细节没有介绍清楚,比如require.optional和default字段的区别是什么,为什么字段前面要写序号等,带着这些疑问,我们需要阅读生成的源码来了解 ...
- 有哪些类型的通知(Advice)?
Before - 这些类型的 Advice 在 joinpoint 方法之前执行,并使用 @Before 注解标记进行配置. After Returning - 这些类型的 Advice 在连接点方法 ...
- servlet中的HttpServletResponse对象
当有多个客户端浏览器去请求Tomcat时,Tomcat会为每一个客户端浏览器创建一对独立的HttpServletRequest与HttpServletResponse对象 HttpServletRes ...
- 攻防世界baby_web
baby_web 题目提示想想初始页,但我们一访问就会跳转到1.php我们使用bp抓包分析,我们发送到repeater模块修改请求访问1.php内容看看 发现flag隐藏了我们去hex中看看 这样我们 ...
- 220v-5v稳压电路
5V整流电路原理 先对电路进行整流 整流电路:利用单向导电器件将交流电转换成脉动直流电路,再用电容进行滤波 滤波电路:利用储能元件(电感或电容)把脉动直流电转换成比较平坦的直流电,然后对电路进行稳压 ...
- mpvue 如何使用腾讯视频插件?
1.在小程序微信开放平台:设置 --- 第三方服务里,申请腾讯视频插件2.申请成功后就可以在项目中使用了 具体使用步骤如下:1.在项目目录src下的main.js中加入下面代码,这里代码会被编译到ap ...
- 如何用vue打造一个移动端音乐播放器
写在前面 没错,这就是慕课网上的那个vue音乐播放器,后台是某音乐播放器的线上接口扒取,虽然这类项目写的人很多,但不得不说这还是个少有的适合vue提升的好项目,做这个项目除了想写一个比较大并且功能复杂 ...