對象是無序屬性的集合
建立自定義對象最簡單的方式就是以字面量的形式建立對象(或建立一個Object實例),而後再爲它添加屬性和方法,以下所示:javascript
var person = { name: "Nicholas", age: 29, sayHi: function() { console.log(this.name); } }
可是咱們須要定義對象中的某個屬性可否修改,可以重寫等屬性,那咱們應該如何定義html
Object.defineProperty()方法介紹(摘自MDN)前端
Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,並返回這個對象
語法:Object.defineProperty(obj, prop, descriptor)
參數:
(1)obj:須要被操做的目標對象
(2)prop:目標對象須要定義或修改的屬性的名稱
(3)descriptor:將被定義或修改的屬性的描述符
返回:被傳遞給函數的對象java
是否能夠刪除目標屬性或是否能夠再次修改屬性的特性(writable, configurable, enumerable)。默認爲false框架
設置爲true能夠被刪除或能夠從新設置特性;
設置爲false,不能被能夠被刪除或不能夠從新設置特性,只能將writable
從true
置爲false
dom
一旦把屬性定義爲不可配置的,就不能再把它便會可配置的,這一點很重要函數
主要起到數據的保護做用,決定了目標屬性是否可使用delete刪除,是否能夠再次設置特性性能
//-----------------測試目標屬性是否能被刪除------------------------ var obj = {} // 第一種狀況:configurable設置爲true,能夠被刪除。 Object.defineProperty(obj, "newKey", { value: "hello", configurable: true }); // 刪除屬性 delete obj.newKey; console.log( obj.newKey ); //undefined // 第二種狀況:configurable設置爲false,不能被刪除。 Object.defineProperty(obj, "newKey", { value: "hello", configurable: false }); // 刪除屬性 delete obj.newKey; console.log( obj.newKey ); //hello //-----------------測試是否能夠再次修改特性------------------------ var obj = {} //第一種狀況:configurable設置爲false,不能再次修改特性。 Object.defineProperty(obj, "newKey", { value: "hello", writable: false, enumerable: false, configurable: false }); //從新修改特性 Object.defineProperty(obj, "newKey", { value: "hello", writable: true, enumerable: true, configurable: true }); console.log( obj.newKey ); //報錯:Uncaught TypeError: Cannot redefine property: newKey //第二種狀況:configurable設置爲true,能夠再次修改特性。 Object.defineProperty(obj, "newKey", { value: "hello", writable: false, enumerable: false, configurable: true }); //從新修改特性 Object.defineProperty(obj, "newKey", { value: "hello", writable: true, enumerable: true, configurable: true }); console.log( obj.newKey ); //hello
此屬性是否能夠被枚舉(使用for...in或Object.keys())默認爲false測試
設置爲true能夠被枚舉;設置爲false,不能被枚舉this
var obj = {} // 第一種狀況:enumerable設置爲false,不能被枚舉。 Object.defineProperty(obj, "newKey", { value: "hello", writable: false, enumerable: false }); // 枚舉對象的屬性 for( var attr in obj ){ console.log( attr ); // undefined } // 第二種狀況:enumerable設置爲true,能夠被枚舉。 Object.defineProperty(obj, "newKey", { value: "hello", writable: false, enumerable: true }); // 枚舉對象的屬性 for( var attr in obj ){ console.log( attr ); //newKey }
屬性對應的值,能夠是任意類型的值,默認爲undefined;
var obj = {} // 第一種狀況:不設置value屬性 Object.defineProperty(obj, "key", {}); console.log( obj.key ); //undefined // 第二種狀況:設置value屬性 Object.defineProperty(obj, "key", { value: "hello" }); console.log( obj.key ); //hello // 同字面定義的數據值對應
屬性的值是否能夠被重寫。默認爲false
設置爲true能夠被重寫;設置爲false,不能被重寫
var obj = {} // 第一種狀況:writable設置爲false,不能重寫。 Object.defineProperty(obj, "newKey", { value: "hello", writable: false }); // 更改newKey的值 obj.newKey = "change value"; console.log( obj.newKey ); //hello // 第二種狀況:writable設置爲true,能夠重寫 Object.defineProperty(obj, "newKey", { value: "hello", writable: true }); // 更改newKey的值 obj.newKey = "change value"; console.log( obj.newKey ); //change value
在調用 Object.defineProperty 方法給對象添加屬性時,若是不指定,configurable、enumerable、writable這些值都爲默認的false
==> 使用 Object.getOwnPropertyDescriptor() 方法來查看對象的內置屬性
var obj = {}; // 第一種狀況:使用 Object.defineProperty() 定義屬性 Object.defineProperty(obj, 'key', { value: "hello" }); Object.getOwnPropertyDescriptor(obj, 'key'); // {value: "hello", writable: false, enumerable: false, configurable: false} // 第二種狀況:字面量方式 obj.key = "hello"; Object.getOwnPropertyDescriptor(obj, 'key'); // {value: "hello", writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor()方法介紹(摘自MDN)
Object.getOwnPropertyDescriptor() 方法返回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不須要從原型鏈上進行查找的屬性)
語法:Object.getOwnPropertyDescriptor(obj, prop)
參數:
(1)obj:須要被操做的目標對象
(2)prop:目標對象內屬性名稱(String類型)
返回:若是指定的屬性存在於對象上,則返回其屬性描述符對象(property descriptor),不然返回 undefined
參照數據屬性中的configurable屬性
參照數據屬性中的enumerable屬性
在讀取屬性是調用的函數,默認值爲undefined
var obj = {}, value = "hello"; Object.defineProperty(obj, 'key', { get: function() { console.log("獲取obj.key的值上下文"); return value; } }); console.log(obj.key); // "獲取obj.key的值上下文" hello obj.key = "new value"; console.log(obj.key); // "獲取obj.key的值上下文" hello
在寫入屬性時調用的函數,默認值爲undefined
// 通常不會單獨爲屬性設置set而不設置get var obj = {}, value = "hello"; Object.defineProperty(obj, 'key', { set: function(val) { console.log("設置obj.key的值上下文"); } }); obj.key = "new value"; // "獲取obj.key的值上下文" console.log(obj.key); // undefined
不必定非要同時指定getter和setter。只指定getter意味着屬性是不能寫,嘗試寫入屬性會被忽略。在嚴格模式下,嘗試寫入只指定getter函數的屬性會拋出錯誤。相似的,只指定setter函數的屬性也不能讀,不然在非嚴格模式下會返回undefined,而在嚴格模式下會拋出錯誤。
var book = { _year: 2004, edition: 1 }; Object.defineProperty(book, "year", { get: function() { return this._year; }, set: function(newValue) { if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } }); book.year = 2005; alert(book.edition); //2
使用訪問器屬性的常見方式,即設置一個屬性的值會致使其餘屬性發生變化
給對象o定義新的屬性b,而且定義屬性b的get和set方法,當o.b的時候會調用b屬性的get方法,給b屬性賦值的時候,會調用set方法,這就是修改數據的時候,視圖會自動更新的關鍵前端獲取數據後,須要根據數據操做dom,視圖變化後,須要修改很多代碼,有沒有方法將數據和dom操做隔離,看一個例子
<!-- 顯示用戶信息的html模版 --> <div> <p>你好,<span id='nickName'></span></p> <div id="introduce"></div> </div>
// 視圖控制器 var userInfo = {}; Object.defineProperty(userInfo, "nickName", { get: function(){ return document.getElementById('nickName').innerHTML; }, set: function(nick){ document.getElementById('nickName').innerHTML = nick; } }); Object.defineProperty(userInfo, "introduce", { get: function(){ return document.getElementById('introduce').innerHTML; }, set: function(introduce){ document.getElementById('introduce').innerHTML = introduce; } }); // 數據 // todo 獲取用戶信息的代碼 // .... userInfo.nickName = "xxx"; userInfo.introduce = "我是xxx,我來自雲南,..."
訪問器屬性是實現MVVM框架的核心原理哦~
Object.defineProperties() 方法直接在一個對象上定義新的屬性或修改現有屬性,並返回該對象
語法:Object.defineProperties(obj, props)
參數:
(1)obj:在其上定義或修改屬性的對象
(2)props:要定義其可枚舉屬性或修改的屬性描述符的對象。對象中存在的屬性描述符主要有數據描述符和訪問器描述符兩種
返回:傳遞給函數的對象
var obj = {}; Object.defineProperties(obj, { 'property1': { value: true, writable: true }, 'property2': { value: 'Hello', writable: false } // etc. etc. });
參考:
Javascript中的Object.defineProperty
MDN Object.defineProperty
MDN Object.getOwnPropertyDescriptor