標籤:case nic any 方法 閉包 define prot 定義 區別
物件導向就是把屬性和操作屬性的方法放在一起作為一個相互依存的整體——對象,即擁有類的概念,基於類可以建立任意多個執行個體對象,一般具有封裝、繼承、多態的特性!
ECMA-262把對象定義為:“無序屬性的集合,其屬性可以包含基本值 對象 或者函數”。這就是說對象是一組沒有特定順序的值,其中值可以是資料或者函數。
雖然Object建構函式或對象字面量都可以建立單個對象,但這些方式有個明顯的缺點,那就是使用同一個介面創造很多個物件,會產生大量的重複代碼。所以產生了下面幾種模式。
1 原廠模式
function createPerson(name,age,job){ var o = {}; o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var tanya = createPerson("tanya","30","female"); tanya.sayName();
特點:這種模式抽象了建立具體對象的過程。它用函數來封裝以特定介面建立對象的細節。
弊端:沒有解決對象識別的問題,而且每次產生一個新對象,都要建立新函數sayName,這使得每個對象都有自己的sayName版本,而事實上,所有的對象都共用同一個函數.
2 建構函式模式
function createPerson(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var tanya =new createPerson("tanya","30","female"); tanya.sayName();
PS:建構函式和普通函數的唯一區別就是調用他們的方式不同:任何函數,只要通過new操作符調用就是建構函式,反之就是普通函數。
使用new操作符建立新執行個體會經曆下面4個步驟:
(1) 建立一個新對象
(2) 將建構函式的範圍賦給新對象(就是this指向了這個新對象)
(3) 執行建構函式中的代碼(為這個新對象添加屬性)
(4) 返回新對象
建構函式和原廠模式的不同之處:
- 沒有顯示的建立對象
- 直接將屬性和方法賦給this對象;
- 沒有return語句
建構函式解決了對象識別的問題(tanya有一個constructor屬性,該屬性指向createPerson),但是就像原廠模式一樣,每個方法都會在每個執行個體中重新建立一遍。我們可以把函數定義轉移到建構函式外部來解決這個問題,但是這樣就沒有封裝性可言了。
3 原型模式
首先介紹一下prototype(原型)屬性,我們建立的每個函數都有一個prototype屬性,這個屬性是一個指標,指向一個對象,而這個對象的用途是包含可以由特定類型的所有執行個體共用的屬性和方法。
PS:JS中萬物皆對象,但分為兩大類:普通對象和函數對象。所有的函數對象都有一個prototype屬性,普通對象是沒有prototype屬性的,只有_proto_。
function createPerson(){ } createPerson.prototype.name = "tanya"; createPerson.prototype.age = "30"; createPerson.prototype.job = "female"; createPerson.prototype.sayName = function(){ alert(this.name); }; var tanya =new createPerson(); tanya.sayName();
原型模式雖然解決了建構函式每個方法都會在每個執行個體中重新建立一遍的問題。但是所有執行個體在預設情況下都取得了相同的屬性值,執行個體一般都是要有屬於自己的全部屬性的。
4 組合使用建構函式模式和原型模式
function createPerson(name,age,job){ this.name = name; this.age = age; this.job = job; } createPerson.prototype.sayName = function(){ alert(this.name); }; var tanya =new createPerson("tanya","30","female"); tanya.sayName();
這是建立自訂類型的最常見方式,建構函式模式定義執行個體屬性,原型模式定義方法和共用的屬性。
5 寄生建構函式模式
function createPerson(name,age,job){ var o = {}; o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var tanya =new createPerson("tanya","30","female"); tanya.sayName();
除了使用new操作符來定義新的對象,以及將其稱之為建構函式之外,其他和原廠模式定義一模一樣。因為建立時用了new,因此使得實現的過程不一樣(但是實現過程不重要),結果一樣。看起來更優雅
寄生建構函式可以在建構函式不適應的情況使用,比如建立具有額外方法的已有類型(如數組,Date類型等),但是又不汙染原有的類型。
6 穩妥建構函式模式
穩妥對象,指的是沒有公用屬性,其方法也不引用this的對象。
穩妥建構函式與寄生建構函式相似,但是有2點不同:新建立對象的執行個體方法不引用this,不使用new操作符調用建構函式。
function createPerson(name, age, job) { var o = new Object(); // private members var nameUC = name.toUpperCase(); // public members o.sayName = function() { alert(name); }; o.sayNameUC = function() { alert(nameUC); }; return o;}var person = Person("Nicholas", 32, "software Engineer");person.sayName(); // "Nicholas"person.sayNameUC(); // "NICHOLAS"alert(person.name); // undefinedalert(person.nameUC); // undefined
凡是想設為 private 的成員都不要掛到 createPerson 返回的對象 o 的屬性上面,掛上了就是 public 的了。這裡的 private 和 public 都是從形式上類比其他 OO 語言來說的,其實現原理還是 js 中範圍、閉包和對象那一套。
JS 建立對象的幾種方式