絕對乾貨!徹底理解Js物件導向程式設計(一)
物件導向(Object-Oriented,OO)的語言有一個標誌,那就是它們都有類的概念,而透過類可
以建立任意多個具有相同屬性和方法的物件。前面提到過,ECMAScript 中沒有類的概念,因
此它的物件也與基於類的語言中的物件有所不同。
ECMA-262 把物件定義為:“無序屬性的集合,其屬性可以包含基本值、物件或者函式。”嚴格來講,
這就相當於說物件是一組沒有特定順序的值。物件的每個屬性或方法都有一個名字,而每個名字都對映
到一個值。正因為這樣(以及其他將要討論的原因),我們可以把 ECMAScript 的物件想象成雜湊表:無
非就是一組名值對,其中值可以是資料或函式。
每個物件都是基於一個引用型別建立的,這個引用型別可以是原生型別,也可以是開發人員定義的型別。
理解屬性型別
在ES5中定義了特性(attribute)描述了屬性(property)的各種特徵。
定義這些特性是為了實現 JavaScript 引擎用的,因此在 JavaScript 中不能直接訪問它們。為了
表示特性是內部值,該規範把它們放在了兩對兒方括號中,例如[[Enumerable]]。
ECMAScript 中有兩種屬性:資料屬性和訪問器屬性。
1. 資料屬性
資料屬性包含一個資料值的位置。在這個位置可以讀取和寫入值。資料屬性有 4 個描述其行為的特性。
[[Configurable]]:表示能否透過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特
性,或者能否把屬性修改為訪問器屬性。像前面例子中那樣直接在物件上定義的屬性,它們的
這個特性預設值為 true。[[Enumerable]]:表示能否透過 for-in 迴圈返回屬性。像前面例子中那樣直接在物件上定
義的屬性,它們的這個特性預設值為 true。[[Writable]]:表示能否修改屬性的值。像前面例子中那樣直接在物件上定義的屬性,它們的
這個特性預設值為 true。[[Value]]:包含這個屬性的資料值。讀取屬性值的時候,從這個位置讀;寫入屬性值的時候,
把新值儲存在這個位置。這個特性的預設值為 undefined。
對於像前面例子中那樣直接在物件上定義的屬性,它們的[[Configurable]]、[[Enumerable]]
和[[Writable]]特性都被設定為 true,而[[Value]]特性被設定為指定的值。例如:
var person = {
name: "Nicholas"
}
這裡建立了一個名為 name 的屬性,為它指定的值是"Nicholas"。也就是說,[[Value]]特性將
被設定為"Nicholas",而對這個值的任何修改都將反映在這個位置。
要修改屬性預設的特性,必須使用 ECMAScript 5 的 Object.defineProperty()方法。這個方法
接收三個引數:屬性所在的物件、屬性的名字和一個描述符物件。其中,描述符(descriptor)物件的屬
性必須是:configurable、enumerable、writable 和 value。設定其中的一或多個值,可以修改
對應的特性值。例如:let person = {}; Object.defineProperty(person, "name", { writable: false, value: "Nicholas" }); alert(person.name); //"Nicholas" person.name = "Greg"; alert(person.name); //"Nicholas"這個例子建立了一個名為 name 的屬性,它的值"Nicholas"是隻讀的。這個屬性的值是不可修改 的,如果嘗試為它指定新值,則在非嚴格模式下,賦值操作將被忽略;在嚴格模式下,賦值操作將會導 致丟擲錯誤。
類似的規則也適用於不可配置的屬性。例如:var person = {}; Object.defineProperty(person, "name", { configurable: false, value: "Nicholas" }); alert(person.name); //"Nicholas" delete person.name; alert(person.name); //"Nicholas把 configurable 設定為 false,表示不能從物件中刪除屬性。如果對這個屬性呼叫 delete,則 在非嚴格模式下什麼也不會發生,而在嚴格模式下會導致錯誤。而且,一旦把屬性定義為不可配置的, 就不能再把它變回可配置了。此時,再呼叫 Object.defineProperty()方法修改除 writable 之外 的特性,都會導致錯誤
var person = {};Object.defineProperty(person, "name", { configurable: false, value: "Nicholas" }); Object.defineProperty(person, "name", { configurable: true, value: "Nicholas" }); //丟擲錯誤也就是說,可以多次呼叫 Object.defineProperty()方法修改同一個屬性,但在把 configurable 特性設定為 false 之後就會有限制了。 在呼叫 Object.defineProperty()方法時,如果不指定,configurable、enumerable 和 writable 特性的預設值都是 false。多數情況下,可能都沒有必要利用 Object.defineProperty() 方法提供的這些高階功能。不過,理解這些概念對理解 JavaScript物件卻非常有用。
2.訪問器屬性
訪問器屬性不包含資料值;它們包含一對兒 getter和 setter函式(不過,這兩個函式都不是必需的)。 在讀取訪問器屬性時,會呼叫 getter函式,這個函式負責返回有效的值;在寫入訪問器屬性時,會呼叫 setter函式並傳入新值,這個函式負責決定如何處理資料。訪問器屬性有如下 4個特性:
[[Configurable]]:表示能否透過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特 性,或者能否把屬性修改為資料屬性。對於直接在物件上定義的屬性,這個特性的預設值為 true。
[[Enumerable]]:表示能否透過 for-in 迴圈返回屬性。對於直接在物件上定義的屬性,這 個特性的預設值為 true。
[[Get]]:在讀取屬性時呼叫的函式。預設值為 undefined。
[[Set]]:在寫入屬性時呼叫的函式。預設值為 undefined。 訪問器屬性不能直接定義,必須使用 Object.defineProperty()來定義。請看下面的例子:
let 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以上程式碼建立了一個 book 物件,並給它定義兩個預設的屬性:_year 和 edition。_year 前面 的下劃線是一種常用的記號,用於表示只能透過物件方法訪問的屬性。而訪問器屬性 year 則包含一個 getter函式和一個 setter函式。getter函式返回_year 的值,setter函式透過計算來確定正確的版本。因此, 把 year 屬性修改為 2005會導致_year 變成 2005,而 edition 變為 2。這是使用訪問器屬性的常見方 式,即設定一個屬性的值會導致其他屬性發生變化。
不一定非要同時指定 getter和 setter。只指定 getter意味著屬性是不能寫,嘗試寫入屬性會被忽略。 在嚴格模式下,嘗試寫入只指定了 getter 函式的屬性會丟擲錯誤。類似地,只指定 setter 函式的屬性也 不能讀,否則在非嚴格模式下會返回 undefined,而在嚴格模式下會丟擲錯誤。
3.定義多個屬性
由於為物件定義多個屬性的可能性很大,ECMAScript 5 又定義了一個 Object.defineProperties()方法。利用這個方法可以透過描述符一次定義多個屬性。這個方法接收兩個物件引數:第一 個物件是要新增和修改其屬性的物件,第二個物件的屬性與第一個物件中要新增或修改的屬性一一對 應。例如:
var book = {}; Object.defineProperties(book, { _year: { value: 2004 }, edition: { 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)。 終的物件與上一節中定義的物件相同。唯一的區別是這裡的屬性都是在同一時間建立的。 支援 Object.defineProperties()方法的瀏覽器有 IE9+、Firefox 4+、Safari 5+、Opera 12+和 Chrome。
6.1.3 讀取屬性的特性
使用 ECMAScript 5的 Object.getOwnPropertyDescriptor()方法,可以取得給定屬性的描述 符。這個方法接收兩個引數:屬性所在的物件和要讀取其描述符的屬性名稱。返回值是一個物件,如果 是訪問器屬性,這個物件的屬性有 configurable、enumerable、get 和 set;如果是資料屬性,這 個物件的屬性有 configurable、enumerable、writable 和 value。例如:
var book = {}; Object.defineProperties(book, { _year: { value: 2004 }, edition: { value: 1 }, year: { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } } }); var descriptor = Object.getOwnPropertyDescriptor(book, "_year"); alert(descriptor.value); //2004alert(descriptor.configurable); //false alert(typeof descriptor.get); //"undefined"var descriptor = Object.getOwnPropertyDescriptor(book, "year"); alert(descriptor.value); //undefined alert(descriptor.enumerable); //falsealert(typeof descriptor.get); //"function"
對於資料屬性_year,value 等於初的值,configurable 是 false,而 get 等於 undefined。 對於訪問器屬性 year,value 等於 undefined,enumerable 是 false,而 get 是一個指向 getter 函式的指標。 在JavaScript中,可以針對任何物件——包括 DOM和BOM物件,使用 Object.getOwnPropertyDescriptor()方法。支援這個方法的瀏覽器有 IE9+、Firefox 4+、Safari 5+、Opera 12+和 Chrome。
作者:alex夏夜
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1806/viewspace-2814871/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JS物件導向程式設計(一):物件JS物件程式設計
- js物件導向程式設計JS物件程式設計
- 理解Js中物件導向程式設計的繼承JS物件程式設計繼承
- JavaScript物件導向程式設計理解!JavaScript物件程式設計
- JS物件導向的程式設計JS物件程式設計
- JS物件導向程式設計(三):原型JS物件程式設計原型
- 看完這篇,真正理解JS物件導向程式設計思想JS物件程式設計
- JS物件導向設計-建立物件JS物件
- Js物件導向(1): 理解物件JS物件
- JS物件導向程式設計(四):繼承JS物件程式設計繼承
- Javascript 物件導向程式設計(一)JavaScript物件程式設計
- JS物件導向設計模式JS物件設計模式
- 物件導向程式設計物件程式設計
- python之物件導向程式設計(一)Python物件程式設計
- js物件導向設計---建立物件的方式JS物件
- JS物件導向程式設計(二):建構函式JS物件程式設計函式
- Python物件導向程式設計Python物件程式設計
- 程式設計思想 物件導向程式設計物件
- 十三、物件導向程式設計物件程式設計
- 十六、物件導向程式設計物件程式設計
- Python 物件導向程式設計Python物件程式設計
- 設計模式:物件導向設計的六大原則 (絕對詳細)設計模式物件
- 如何理解物件導向(一)物件
- 物件導向程式設計C++物件程式設計C++
- Python OOP 物件導向程式設計PythonOOP物件程式設計
- python技能--物件導向程式設計Python物件程式設計
- javascript:物件導向的程式設計JavaScript物件程式設計
- Javascript 物件導向程式設計(二)JavaScript物件程式設計
- Javascript 物件導向程式設計(三)JavaScript物件程式設計
- 06 物件導向程式設計 (續)物件程式設計
- Python物件導向程式設計(1)Python物件程式設計
- Scala的物件導向程式設計物件程式設計
- Python - 物件導向程式設計 - super()Python物件程式設計
- Python - 物件導向程式設計 - @propertyPython物件程式設計
- SpringBoot 併發程式設計學習歷程(絕對的乾貨)Spring Boot程式設計
- js-物件導向-設計模式-命令模式JS物件設計模式
- 學半年程式設計才知道“物件導向”可以這樣理解程式設計物件
- 新手如何理解JS物件導向開發?JS物件