1. 程式人生 > >JS筆記: 第6章 js中面向物件的理解

JS筆記: 第6章 js中面向物件的理解

6面向物件的程式設計

理解物件:

ECMA-262把物件定義為:“無序屬性的集合,其屬性可以包含基本值、物件或者函式。”

建立自定義物件的最簡單方式就是建立一個Object的例項,然後再為它新增屬性和方法。幾年後,物件字面量成為建立這種物件的首選模式。

屬性型別:資料屬性和訪問器屬性。

要修改屬性預設的特性,必須使用ECMAScript 5Object.defineProperty()方法。

訪問器屬性不包含資料值,它們包含一對gettersetter函式。使用訪問器屬性的常見方式,即設定一個屬性的值會導致其他屬性發生變化。

ECMAScript 5又定義了一個Object.defineProperties()方法,利用這個方法可以通過描述符一次性定義多個屬性。

讀取屬性特性:使用ECMAScript 5Object.getOwnPropertyDescriptor()方法,可以取得給定屬性的描述符。

建立物件:

物件的constructor屬性最初是用來標識物件型別的。但是,提到檢測物件型別,還是instanceof操作符要更靠譜一些。

建構函式與其他函式的唯一區別,就在於呼叫它們的方式不同。任何函式,只要通過new操作符來呼叫,那它就可以作為建構函式。

不通過new操作符呼叫建構函式Person()會出現什麼結果:屬性和方法都被新增給了window物件了。

建構函式問題:使用建構函式的主要問題,就是每個方法都要在每個例項上重新建立一遍。通過把函式定義轉移到建構函式外部來解決這個問題。但又引起了一個新問題,就是沒有了封裝性可言,可通過原型模式來解決。

原型模式:我們建立的每個函式都有一個prototype屬性,這個屬性是一個指標,指向一個物件,即原型物件。使用原型物件的好處是可以讓所有物件例項共享它包含的屬性和方法。

理解原型物件:

當呼叫建構函式建立一個新例項後,該例項的內部將包含一個指標,指向建構函式的原型物件。ECMAScript 5中管這個指標叫[[prototype]]。雖然在指令碼中沒有標準的方式訪問[[prototype]],但FirefoxChrome在每個物件都支援一個__proto__屬性。

雖然在所有實現中都無法訪問到[[prototype]],但可以通過isPrototypeOf()方法來確定物件之間是否存在這種關係。

ECMAScript 5增加了一個新方法,叫

Object.getPrototypeOf(),這個方法返回[[Prototype]]的值。

使用hasOwnProperty()方法可以檢測一個屬性是存在於例項中,還是存在於原型中。

在使用in操作符、for-in時,返回的是所有能夠通過物件訪問的、可列舉的屬性,其中既包括存在於例項中的屬性,也包括存在於原型中的屬性。

預設不可列舉的所有屬性和方法,包括:hasOwnProperty()、propertyIsEnumerable()、toLocaleString()、toString()和valueOf()、constructorprototype

要取得物件上所有可列舉的例項屬性,可以使用ECMAScript 5Object.keys()方法。

如果你想要得到所有例項屬性,無論是否可列舉,都可以使用Object.getOwnPropertyNames()。

重寫原型物件切斷了現有原型與任何之前已經存在的物件例項之間的聯絡,它們引用的仍然是最初的原型。

建立自定義型別的最常見方式,就是組合使用建構函式模式與原型模式。建構函式模式用於定義例項屬性,而原型模式用於定義方法和共享的屬性。

繼承:

許多OO語言都支援兩種繼承方式:介面繼承和實現繼承。ECMAScript只支援實現繼承,而且其實現繼承主要是依靠原型鏈來實現的。

建構函式、原型和例項之間的關係:每個建構函式都有一個原型物件,原型物件都包含一個指向建構函式的指標,而例項都包含一個指向原型物件的內部指標。

給原型新增方法的程式碼一定要放在替換原型的語句之後。

原型鏈問題:

1)最主要的問題來自包含引用型別值的原型,這類原型屬性會被所有例項共享。這也是為什麼要在建構函式中,而不是原型物件中定義屬性的原因。

2)第二個問題是在建立子型別的例項時,不能向超型別的建構函式中傳遞引數。

在解決原型中包含引用型別值所帶來問題的過程中,開發人員開始使用一種叫做借用建構函式的技術,即在子型別建構函式的內部呼叫超型別的建構函式。

小結:

在沒有類的情況下,可以採用下列模式建立物件:

1)工廠模式,使用簡單的函式建立物件,為物件新增屬性和方法,然後返回物件。這個模式後來被建構函式模式所取代。

2)建構函式模式,可以建立自定義引用型別,使用new操作符。不過建構函式也有缺點,即它的每個成員都無法得到複用,包括函式。

3)原型模式,使用建構函式的prototype屬性來指定那些應該共享的屬性和方法。

JavaScript主要通過原型鏈實現繼承。原型鏈的構建是通過將一個型別的例項賦值給另一個建構函式的原型實現的。問題是物件例項共享所有繼承的屬性和方法,因此不適宜單獨使用。解決這個問題的技術是借用建構函式,即在子型別建構函式內部呼叫超型別建構函式。