衆所周知,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裏面是怎麼處理的呢。 我們下次再一起學習。