1、vue雙向數(shù)據(jù)綁定原理圖

132184689-57b310ea1804f_articlex.png
2、基礎(chǔ)補(bǔ)充
(1)Object.keys(obj) :作用:獲取對(duì)象的所有屬性,返回屬性數(shù)組
let obj = {
a:12,
b:'abc',
c:['a','b']
}
let keys = Object.keys(obj)
console.log(keys)
//結(jié)果:["a","b","c"]
//獲取對(duì)象的值
keys.forEach((key) => {
keys.forEach((key) => {
console.log( 'key='+key, 'value='+obj[key])
})
//結(jié)果:
//key=a value=12
//key=b value=abc
//key=c value=a,b

Object.keys(obj).png
(2)Object.defineProperty(obj,prop,descriptor) 方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性, 并返回這個(gè)對(duì)象。在vue中可以理解為:使用這個(gè)方法使對(duì)象變得“可觀測(cè)”
參數(shù)
obj
要在其上定義屬性的對(duì)象。
prop
要定義或修改的屬性的名稱。
descriptor
將被定義或修改的屬性描述符。
返回值
被傳遞給函數(shù)的對(duì)象。
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
}
})
//默認(rèn)情況下,會(huì)先執(zhí)行g(shù)et函數(shù),當(dāng)屬性值發(fā)生變化,才會(huì)執(zhí)行set函數(shù),再執(zhí)行g(shù)et函數(shù)

Object.defineProperty.png
(2)實(shí)現(xiàn)代碼
一、使數(shù)據(jù)對(duì)象變得“可觀測(cè)”
/**
* 使一個(gè)對(duì)象轉(zhuǎn)化成可觀測(cè)對(duì)象
* @param { Object } obj 對(duì)象
* @param { String } key 對(duì)象的key
* @param { Any } val 對(duì)象的某個(gè)key的值
*/
function defineReactive (obj, key, val) {
Object.defineProperty(obj,key, {
get(){
console.log('我的屬性值被讀取了='+key)
return val
},
set(newValue){
console.log('我的屬性被修改了='+newValue);
return newValue
}
})
}
/**
* 把一個(gè)對(duì)象的每一項(xiàng)都轉(zhuǎn)化成可觀測(cè)對(duì)象
* @param { Object } obj 對(duì)象
*/
function observable (obj) {
const keys = Object.keys(obj);
keys.forEach((key) =>{
defineReactive(obj, key,obj[key])
})
return obj;
}
//現(xiàn)在我們可以把英雄這么定義:
const obj1= observable({
a: 3000,
b: 150
})

使數(shù)據(jù)對(duì)象變得“可觀測(cè)”.png
二、依賴收集
目的:讓對(duì)象主動(dòng)發(fā)出通知的功能
思路:當(dāng)可觀測(cè)對(duì)象的屬性被讀寫時(shí),就會(huì)觸發(fā)getter和seter方法,可以在geter和seter方法,去執(zhí)行監(jiān)聽器里面的onComputedUpdate()方法,由于onComputedUpdate()需要接收回到函數(shù)的返回值作為參數(shù),而可觀測(cè)對(duì)象中并沒有回調(diào)函數(shù),所以需要一個(gè)能夠收集監(jiān)聽器內(nèi)的回調(diào)函數(shù)的值以及onComputedUpdate()方法的依賴收集器
/**
* 定義一個(gè)“依賴收集器”
*/
const Dep = {
target: null
}
/**
* 使一個(gè)對(duì)象轉(zhuǎn)化成可觀測(cè)對(duì)象
* @param { Object } obj 對(duì)象
* @param { String } key 對(duì)象的key
* @param { Any } val 對(duì)象的某個(gè)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()
})
}
})
}
/**
* 把一個(gè)對(duì)象的每一項(xiàng)都轉(zhuǎn)化成可觀測(cè)對(duì)象
* @param { Object } obj 對(duì)象
*/
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
}
/**
* 當(dāng)計(jì)算屬性的值被更新時(shí)調(diào)用
* @param { Any } val 計(jì)算屬性的值
*/
function onComputedUpdate (val) {
console.log(`我的類型是:${val}`)
}
/**
* 觀測(cè)者
* @param { Object } obj 被觀測(cè)對(duì)象
* @param { String } key 被觀測(cè)對(duì)象的key
* @param { Function } cb 回調(diào)函數(shù),返回“計(jì)算屬性”的值
*/
function watcher (obj, key, cb) {
// 定義一個(gè)被動(dòng)觸發(fā)函數(shù),當(dāng)這個(gè)“被觀測(cè)對(duì)象”的依賴更新時(shí)調(diào)用
const onDepUpdated = () => {
const val = cb()
onComputedUpdate(val)
}
Object.defineProperty(obj, key, {
get () {
Dep.target = onDepUpdated
// 執(zhí)行cb()的過程中會(huì)用到Dep.target,
// 當(dāng)cb()執(zhí)行完了就重置Dep.target為null
const val = cb()
Dep.target = null
return val
},
set () {
console.error('計(jì)算屬性無(wú)法被賦值!')
}
})
}
const obj= observable({
a: 3000,
b: 150
})
watcher(obj, 'd', () => {
return obj.a > 1000 ? '坦克' : '脆皮'
})

result.png