一、對象
這個不用多說,常見的幾種創建對象的方法有:
1.通過構造函數創建對象,如下所示:
function Person(){ } var person = new Person();
2.通過Object創建簡單對象,例如:
var obj = new Object();
3.通過字面量創建對象。
var obj = {};
常用的一般是第一種和第三種方法。
二、屬性類型
javascript中有兩種屬性:數據屬性和訪問器屬性,確切的說這兩種特性是用來描述對象屬性的各種特征,比如說這個對象屬性的值能否被改變,因為這些特性是內部值,而javascript又不能直接訪問,所以在規范中把他們放在了兩對兒化括號中,例如[[Enumerable]]。下面 來看看這兩種具體的內部屬性。
1.數據屬性
數據屬性包含一個數據值。在這個位置可以讀取和寫入值,
[[Configurable]]:表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,能否把屬性修改為訪問器屬性(這個后面會說),默認為true;
[[Enumerable]]:用來修飾對象屬性的枚舉特性,表示能否通過用for in循環返回屬性,默認為true;
[[Writable]]:用來修飾對象屬性值的可寫特性,默認為true;
[[Value]]:包含這個屬性的數據值,訪問器屬性里面是沒有這個特性的。默認為undefined;比如var person = {name:'lili'},這里設置了一個名叫name的屬性,它的值是"lili", [[Value]]特性將被設置為"lili",其余的是三個特性都是默認值true。
下面就用具體的實例來理解上面的特性。首先這里要先談的是Object.defineProperty()方法,這個方法接收三個參數:屬性所在的對象、屬性的名字、和一個描述符對象(也就是上面的四個數據屬性,用來描述對象屬性的特性),這里要注意了,采用Object.defineProperty方法創建屬性時候,數據屬性[[configurable]]、[[writable]]、[[enumerable]]默認為false,這要和字面量直接聲明屬性時默認值相反,但是如果只是用Object.defineProperty改變原來已有屬性的值則沒有此限制,具體看下面例子:
var person = {};
Object.defineProperty(person,'name',{ //創建name屬性
value:'lili',
});
console.log(person.name); //lili
person.name = 'shasha'; //writable默認是false 不可改動屬性值
console.log(person.name); //lili
修改writable的值為true可以看到,person.name的值打印出來是'shasha';
var person = {}; Object.defineProperty(person,'name',{//創建name屬性 writable:true, value:'lili', }); console.log(person.name); //lili person.name = 'shasha'; //writable設置為true, 屬性值被重寫 console.log(person.name); //shasha
但是當person里面有屬性,采用Object.defineProperty方法只是修改特性和值時,默認值都為true,具體請看下面示例:
var person = {age:22}; Object.defineProperty(person,'age',{ //重新定義修改age屬性 value:33, }); person.age = 66; console.log(person.age); //66 說明writable此時為true,
設置[[enumrable]]特性的規則跟[[writable]]相同,為true時才能用for in 循環遍歷出屬性。下面來重點看看[[Configurable]]特性的作用,例子如下:
var person = {}; Object.defineProperty(person,'name',{ configurable:false, value:'lili', }); console.log(person.name); //lili delete person.name; console.log(person.name); //lili
把configurable設置為false,表示不能刪除對象屬性,對這個這個屬性調用delete方法,非嚴格模式下什么也不會發生,嚴格模式下則會拋出錯誤,而且一旦把屬性從configurable設置為false,以后就不能把它設置為true,此時在調用Object.defineProperty方法修改除writable、value之外的特性,都會導致錯誤,看下面例子:
var person = {}; Object.defineProperty(person, 'name', { configurable: false, enumerable: true, writable: true, value: 'lili', }); Object.defineProperty(person, 'name', { // configurable: true, //會報錯額! // enumerable: false, //會報錯的! writable: false, value: 'tangtang', }); person.name = 'wangdachui'; console.log(person.name);//tangtang
2.訪問器屬性
訪問器屬性不包括數據值,它包含一對getter和setter函數,在讀取訪問器屬性時,會調用getter函數,這個函數負責返回有效的值;在寫入訪問器屬性時,會調用setter函數並傳入新值,訪問器屬性有如下四個特性:
[[Configurable]]:表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,能否把屬性修改為數據屬性(這個后面會說),默認為true;
[[Enumerable]]:用來修飾對象屬性的枚舉特性,表示能否通過用for in循環返回屬性,默認為true;
[[Get]]:在讀取屬性時候調用的函數,默認為undeifne;
[[Set]]:在寫入屬性時候調用的函數,默認為undeifne;
訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義。請看下面的例子。
var book = { _year: 2018, edition: 1, }; Object.defineProperty(book, 'year', { get: function () { alert('通過對象方法訪問 哈哈!'); return this._year; }, set: function (newValue) { if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; alert(this.edition); } } }); console.log(book.year) //通過對象方法訪問 get函數里面alert出對應信息; book.year = 2005; console.log(book.edition); //2
以上例子中,book對象有兩個默認屬性:_year 和 edition ,其中_year前面加了下划線,用於表示只能通過對象方法去訪問這個屬性,即通過get方法返回屬性值。如果直接訪問book.edition的值,則不會調用get方法返回。book.year=2005即是修改book的year屬性值,會調用set方法,參數newValue就是設置的2005這個值,在上面例子中set函數里還改變了屬性edition的值。
3.定義多個屬性
采用Object.defineProperties我們也可以為一個對象定義多個屬性,這個方法有兩個參數:第一個要定義屬性的對象,第二個也是對象,表示要添加的多個屬性和其對應的屬性描述符,具體怎么添加呢,請看下面的例子:
var book = {}; Object.defineProperties(book,{ _year:{ writable:true, value:2004, }, edition:{ writable:true, value:1, }, year:{ get:function(){ return this._year; }, set:function(newValue){ if(newValue > 2004){ this._year = newValue; this.edition += newValue - 2004; } } } });
以上代碼在book對象上定義了兩個數據屬性(_year和edition)和一個訪問器屬性(year)。
4.讀取屬性的特性
上面我們一直是在討論如何設置屬性的描述特性,那么對於數據屬性和訪問器屬性里面的具體特性我們怎么讀取呢?這里介紹另一個Object的方法:getOwnPropertyDescriptor方法,該方法接收兩個參數:屬性所在的對象和要讀取其描述符的屬性名稱,它的返回是一個對象,來我們來看看具體的實例:
var book = {}; Object.defineProperties(book, { _year: { writable: true, value: 2004, }, edition: { writable: true, value: 1, }, year: { get: function () { return this._year; }, set: function (newValue) { if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } } }); book.year = 2005; console.log(book.edition); //2 var descriptor1 = Object.getOwnPropertyDescriptor(book, '_year'); console.log(descriptor1.value); //2005 console.log(descriptor1.configurable);//false console.log(typeof descriptor1.get); //undefine var descriptor2 = Object.getOwnPropertyDescriptor(book, 'year'); console.log(descriptor2.value); //2005 console.log(descriptor2.configurable);//false console.log(typeof descriptor2.get); //function;
