閱讀目錄
- 一:理解普通對象在聲明時添加 get、set
- 二:Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__
- 三:Object.defineProperty
- 四:Object.defineProperties
- 五:Proxy
一:理解普通對象在聲明時添加 get、set
在做vue的時候,我們經常會看到 data里面的屬性 都有 get 和 set方法,如下所示:

如上vue中data里面它有兩個屬性,一個xxx 數組 和 一個 testA對象,但是都有get和set方法。也就是說在vue中data里面的每個屬性都有兩個相對應的get和set方法。為什么會有這樣的呢?下面我們先來看一個普通的對象,如下代碼所示:
const obj = { name: 'kongzhi', _age: 30, get age() { return this._age; }, set age(x) { this._age = x; } }; console.log(obj);
打印會如下所示:

當我們繼續打印如下信息:
console.log(obj._age); // 輸出:30 console.log(obj.age); // 輸出:30 // 設置值 obj.age = 31; console.log(obj.age); // 輸出:31 console.log(obj.age()); // Uncaught TypeError: obj.age is not a function
如上代碼演示所示,我們在對象里面使用 get 或 set定義的 age, 它只是obj中的一個屬性,它並不是方法,因此如上我們使用獲取屬性的值或設置屬性的值操作是正常的,當我們使用 obj.age() 把它當做一個方法調用的時候,它會報錯。因此在vue中所有的屬性有get、set這樣的,當我們自動給某個屬性賦值的時候,它會自動調用 set對應的方法,當我們獲取某個屬性的時候,它會自動調用get方法。但是我們不能手動調用 set/get xxx() 中的xxx這樣的方法。
二:Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__
上面只是在聲明obj對象的時候,編寫get和set 對應的屬性。但是如果已經存在的對象的時候,再想繼續添加 get/set呢?那只有使用
Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__ 了,如下代碼演示:
const obj = { name: 'kongzhi', _age: 30 }; obj.__defineGetter__('age', function(){ console.log('監聽到正在獲取屬性age的值'); return this._age; }); obj.__defineSetter__('age', function(value) { console.log('監聽到正在設置屬性age的值為:' + value); this._age = value; }); /* * 打印:監聽到正在獲取屬性age的值 * 輸出:30 */ console.log(obj.age); // 打印:監聽到正在設置屬性age的值為:31 obj.age = 31; /* * 打印:監聽到正在獲取屬性age的值 * 輸出: 31 */ console.log(obj.age);
但是呢?Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__ 這個方法已經不推薦使用了,並且隨着以后瀏覽器的發展,可能會不再支持該方法,那怎么辦呢?當然會有新的替代方案的,我們繼續往下講。
三:Object.defineProperty
該方法它是由兩部分組成,分別是:數據描述符和訪問器描述符,數據描述符的含義是:它是一個包含屬性的值,並說明這個屬性值是可讀或不可讀的對象。訪問器描述符的含義是:包含該屬性的一對 getter/setter方法的對象。
那么具體項了解該方法的使用及詳解,請看我這篇文章(https://www.cnblogs.com/tugenhua0707/p/10261170.html),下面看使用 Object.defineProperty 來監聽對象屬性值的變化,如下代碼:
const obj = { name: 'kongzhi', _age: 30 }; Object.defineProperty(obj, 'age', { get() { console.log('監聽到正在獲取屬性age的值'); return this._age; }, set(value) { console.log('監聽到正在設置屬性age的值為:' + value); this._age = value; return this._age; } }); /* * 打印:監聽到正在獲取屬性age的值 * 輸出:30 */ console.log(obj.age); // 打印:監聽到正在設置屬性age的值為:31 obj.age = 31; /* * 打印:監聽到正在獲取屬性age的值 * 輸出: 31 */ console.log(obj.age);
四:Object.defineProperties
Object.defineProperties 是對 Object.defineProperty的擴展的,它可以一次性添加多個/修改多個對象屬性描述符。
如下代碼演示:
const obj = { _name: 'kongzhi', _age: 30 }; Object.defineProperties(obj, { age: { get() { console.log('監聽到正在獲取屬性age的值'); return this._age; }, set(value) { console.log('監聽到正在設置屬性age的值為:' + value); this._age = value; return this._age; } }, name: { get() { console.log('監聽到正在獲取屬性name的值'); return this._name; }, set(value) { console.log('監聽到正在設置屬性name的值為:' + value); this._name = value; return this._name; } } }); /* * 打印:監聽到正在獲取屬性age的值 * 輸出:30 */ console.log(obj.age); // 打印:監聽到正在設置屬性age的值為:31 obj.age = 31; /* * 打印:監聽到正在獲取屬性age的值 * 輸出: 31 */ console.log(obj.age); console.log('-------下面是對象name屬性的監聽-------'); /* * 打印:監聽到正在獲取屬性name的值 * 輸出:kongzhi */ console.log(obj.name); // 打印:監聽到正在設置屬性name的值為:longen obj.name = 'longen'; /* * 打印:監聽到正在獲取屬性name的值 * 輸出: longen */ console.log(obj.name);
五:Proxy
那么具體了解Proxy是啥,是干啥使用的,請看我這篇文章(https://www.cnblogs.com/tugenhua0707/p/10306793.html);
那么它也可以監聽對象屬性值的變化,如下代碼演示:
const target = { name: 'kongzhi' }; const handler = { get: function(target, key) { console.log(`${key} 被讀取`); return target[key]; }, set: function(target, key, value) { console.log(`${key} 被設置為 ${value}`); target[key] = value; } }; const testObj = new Proxy(target, handler); /* 獲取testObj中name屬性值 會自動執行 get函數后 打印信息:name 被讀取 及輸出名字 kongzhi */ console.log(testObj.name); /* 改變target中的name屬性值 打印信息如下: name 被設置為 111 */ testObj.name = 111; console.log(target.name); // 輸出 111
