1、vue双向数据绑定原理图
132184689-57b310ea1804f_articlex.png
2、基础补充
(1)Object.keys(obj) :作用:获取对象的所有属性,返回属性数组
let obj = {
a:12,
b:'abc',
c:['a','b']
}
let keys = Object.keys(obj)
console.log(keys)
//结果:["a","b","c"]
//获取对象的值
keys.forEach((key) => {
keys.forEach((key) => {
console.log( 'key='+key, 'value='+obj[key])
})
//结果:
//key=a value=12
//key=b value=abc
//key=c value=a,b
Object.keys(obj).png
(2)Object.defineProperty(obj,prop,descriptor) 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。在vue中可以理解为:使用这个方法使对象变得“可观测”
参数
obj
要在其上定义属性的对象。
prop
要定义或修改的属性的名称。
descriptor
将被定义或修改的属性描述符。
返回值
被传递给函数的对象。
let obj = {
a:12,
b:'abc',
c:['a','b']
}
let val = 2000;
let key ='a';
Object.defineProperty(obj,key, {
get(){
console.log('我的属性值被读取了='+key)
return val
},
set(newValue){
console.log('我的属性被修改了='+newValue);
return newValue
}
})
//默认情况下,会先执行get函数,当属性值发生变化,才会执行set函数,再执行get函数
Object.defineProperty.png
(2)实现代码
一、使数据对象变得“可观测”
/**
* 使一个对象转化成可观测对象
* @param { Object } obj 对象
* @param { String } key 对象的key
* @param { Any } val 对象的某个key的值
*/
function defineReactive (obj, key, val) {
Object.defineProperty(obj,key, {
get(){
console.log('我的属性值被读取了='+key)
return val
},
set(newValue){
console.log('我的属性被修改了='+newValue);
return newValue
}
})
}
/**
* 把一个对象的每一项都转化成可观测对象
* @param { Object } obj 对象
*/
function observable (obj) {
const keys = Object.keys(obj);
keys.forEach((key) =>{
defineReactive(obj, key,obj[key])
})
return obj;
}
//现在我们可以把英雄这么定义:
const obj1= observable({
a: 3000,
b: 150
})
使数据对象变得“可观测”.png
二、依赖收集
目的:让对象主动发出通知的功能
思路:当可观测对象的属性被读写时,就会触发getter和seter方法,可以在geter和seter方法,去执行监听器里面的onComputedUpdate()方法,由于onComputedUpdate()需要接收回到函数的返回值作为参数,而可观测对象中并没有回调函数,所以需要一个能够收集监听器内的回调函数的值以及onComputedUpdate()方法的依赖收集器
/**
* 定义一个“依赖收集器”
*/
const Dep = {
target: null
}
/**
* 使一个对象转化成可观测对象
* @param { Object } obj 对象
* @param { String } key 对象的key
* @param { Any } val 对象的某个key的值
*/
function defineReactive (obj, key, val) {
const deps = []
Object.defineProperty(obj, key, {
get () {
console.log(`我的${key}属性被读取了!`)
if (Dep.target && deps.indexOf(Dep.target) === -1) {
deps.push(Dep.target)
}
return val
},
set (newVal) {
console.log(`我的${key}属性被修改了!`)
val = newVal
deps.forEach((dep) => {
dep()
})
}
})
}
/**
* 把一个对象的每一项都转化成可观测对象
* @param { Object } obj 对象
*/
function observable (obj) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i], obj[keys[i]])
}
return obj
}
/**
* 当计算属性的值被更新时调用
* @param { Any } val 计算属性的值
*/
function onComputedUpdate (val) {
console.log(`我的类型是:${val}`)
}
/**
* 观测者
* @param { Object } obj 被观测对象
* @param { String } key 被观测对象的key
* @param { Function } cb 回调函数,返回“计算属性”的值
*/
function watcher (obj, key, cb) {
// 定义一个被动触发函数,当这个“被观测对象”的依赖更新时调用
const onDepUpdated = () => {
const val = cb()
onComputedUpdate(val)
}
Object.defineProperty(obj, key, {
get () {
Dep.target = onDepUpdated
// 执行cb()的过程中会用到Dep.target,
// 当cb()执行完了就重置Dep.target为null
const val = cb()
Dep.target = null
return val
},
set () {
console.error('计算属性无法被赋值!')
}
})
}
const obj= observable({
a: 3000,
b: 150
})
watcher(obj, 'd', () => {
return obj.a > 1000 ? '坦克' : '脆皮'
})
result.png