众所周知,vue2.0的双向数据绑定使用es6的Object.defineProperty方法实现的,本文我讲会为大家仔细讲解之间的实现原理。
- Object.defineProperty() 法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
这个方法接收三个参数,
Object.defineProperty(obj, prop, desc)
- obj 需要定义属性的当前对象.
- prop 当前需要定义的属性名.
- desc 属性描述符(configurable, enumerable, writable, set, get)
其实我们平时给对象添加属性例如
let obj = {};
obj.name = 'lisi';
用Object.defineProperty()的话就是
var o = {};
Object.defineProperty(o, 'name', {
enumerable: true,// 可被枚举, 就是for in 循环能得到key
configurable: true, // 能够被改变,能够被删除。
writable: true, // 可被赋值改变
value: "list"
})
在我们的vue中其实就是利用Object.defineProperty中的get和set方法,获取对象的值的时候会触发get方法,设置值的时候会触发set方法,从而去通知订阅的对象达到响应式。注意: 设置了get,set 就不能设置writable属性了否则会报错。
var o = {};
var value = '';
Object.defineProperty(o, 'name', {
enumerable: true,
configurable: true,
// writable: true,
get() {
return value
},
set(newValue) {
value = newValue;
}
})
了解了上面Object.defineProperty()的基本用法,我们来模仿vue中对数据的劫持。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var obj = {
name: 'yumang',
age: 18,
girls: ['美女']
};
function defineReactive(o, key, value){
if (typeof value === 'object' && value != null && !Array.isArray(value)) {
// 是非数组的引用类型
reactify(value); // 递归
}
Object.defineProperty(o, key ,{
configurable:true,
enumerable:true,
get(){
// get 的时候做额外操作
console.log('这里在获取'+ key + '的值')
return value
},
set(newValue){
// set 的时候做额外操作
console.log('这里在设置' + key + '的值'+ newValue)
value = newValue;
},
})
}
/**
* o 要被劫持的对象
* **/
function reactify (o){
let keys = Object.keys(o);
for (let i=0; i< keys.length; i++ ){
let key = keys[i];
let value = o[key];
/**
* 1. 数组监听
* 2. 对象和普通值的监听
* **/
if (Array.isArray(value)){
// 如果是数组 就要对数组里面的每一个属性进行监听
for(let j = 0; j< value.length; j ++) {
if (typeof value[j] === 'object') reactify(value[j]) // 递归
}
}else {
// 对象和普通值的监听, 进入defineReactive的时候 如果对象里面还有对象就需要使用递归
defineReactive(o, key, value)
}
}
}
reactify(obj)
</script>
</body>
</html>
以上两个函数的递归调用我们就完成了对象属性的监听, 然而对于数组, 它的一些方法push等,却没有监听到,vue里面是怎么处理的呢。 我们下次再一起学习。