Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。javascript
Vue2.x使用屬性裏的get和set實現了數據響應。html
經常使用屬性:vue
value:該屬性對應的值。能夠是任何有效的 JavaScript 值(數值,對象,函數等)。默認爲 undefined
。java
get:一個給屬性提供 getter 的方法,若是沒有 getter 則爲 undefined
。當訪問該屬性時,該方法會被執行,方法執行時沒有參數傳入,可是會傳入this
對象(因爲繼承關係,這裏的this
並不必定是定義該屬性的對象)。 默認爲 undefined
。數組
set:一個給屬性提供 setter 的方法,若是沒有 setter 則爲 undefined
。當屬性值修改時,觸發執行該方法。該方法將接受惟一參數,即該屬性新的參數值。 默認爲 undefined
。app
writeable:當且僅當該屬性的writable
爲true
時,value
才能被賦值運算符改變。默認爲 false
。dom
enumrable:當且僅當該屬性的enumerable
爲true
時,該屬性纔可以出如今對象的枚舉屬性中。默認爲 false
。函數
configurable: 當且僅當該屬性的 configurable 爲 true 時,該屬性描述符纔可以被改變,同時該屬性也能從對應的對象上被刪除。默認爲 false
。ui
實例:在頁面上初始化「I am Hector」,延時2s,修改「Hector」部分的值,修改成「Hector Real」,頁面顯示「I am Hector Real」,實現數據響應。this
建立頁面:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>LearnVue3.0</title>
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src="test.js"></script>
<script type="text/javascript"> const vm = new vue(); // 延時2s修改數據 setTimeout(function () { console.log('change'); console.log(vm.$data); vm.$data.a = 'Hector Real'; }, 2000); </script>
</body>
</html>
複製代碼
test.js中使用Object.defineProperty
實現數據響應:
function vue() {
// 固定對象和dom
this.$data = {
a: 'Hector'
};
this.el = document.getElementById('app');
// 須要渲染的文字
this._html = "";
// 初始化
this.observe(this.$data);
this.render();
}
// 數據監聽
vue.prototype.observe = function (obj) {
let self = this;
let value;
// 解決只能對某個屬性進行defineProperty的問題
// 因此針對傳入obj進行了for-in遍歷
for (let key in obj) {
value = obj[key];
if (typeof value === 'object') {
// 再對這個對象設置監聽
this.observe(value);
} else {
Object.defineProperty(this.$data, key, {
// 依賴收集
get: function () {
return value;
},
// 觸發更新
set: function (newvalue) {
value = newvalue;
self.render();
}
})
}
}
}
// 渲染
vue.prototype.render = function () {
this._html = "I am " + this.$data.a;
this.el.innerHTML = this._html;
}
複製代碼
在Chrome中運行,結果頁面顯示: I am Hector Real
在Chrome的console中的log:
針對數組特性化處理:
let arraypro = Array.prototype;
// 爲何要create再次建立對象,create是深拷貝,不影響以前的arraypro
let arrayob = Object.create(arraypro);
// 定義哪些方法觸發更新
let arr = ["push", "pop", "shift"];
// arr裏的方法,既能保持原有方法,又能觸發更新
// 裝飾者模式
arr.forEach(function (method, index) {
// 對本身的push方法重寫
arrayob[method] = function () {
let ret = arraypro[method].apply(this, arguments);
// self.render();
console.log('檢測到數組變化,觸發更新');
return ret;
}
});
複製代碼
在Chrome中console運行示例:
let arr = [];
arr.__proto__ = arrayob;
arr.push(1);
複製代碼
結果顯示:
歡迎關注個人公衆號,謝謝你們!