標籤:code 共用 job 不同的 缺點 特定 對象 標識 建立
物件導向(Object-Oriented,OO)的語言有一個特點,那就是它們都有類的概念。而javascript中沒有類的概念,因此它的對象也與基於類的語言中的對象有所不同。
ECMA-262把對象定義為:“無序屬性的集合,其屬性可以包含基本值、對象或函數”,我們可以把對象想象成散列集:無非就是一組名值對,其中值可以是資料或函數。下面介紹幾種建立對象的按方法。
一、Object建構函式或對象字面量
var person={ name:"Bob", age:"24", sayName:function(){ alert(this.name); } }
這種方法有明顯缺陷:會產生大量重複代碼。
二、原廠模式
考慮到ECMAscript中無法建立類,開發人員想到用函數封裝以特定介面建立對象的細節。
function createPerson(name,age){ return { name:name, age:age, sayName:function(){ alert(this.name); } } } var person1=createPerson("Bob","24");
原廠模式雖然定義介面建立對象,單卻沒有解決對象識別的問題(即怎樣知道一個對象的類型)。
三、建構函式模式
大家都知道在javascript中用建構函式可建立特定類型的對象,如:Object、Array。此外,也可以建立自訂的建構函式,從而定義自訂物件類型的屬性和方法。
function Person(name,age){ this.name=name; this.age=age; this.sayName=function(){ alert(this.name); } } var person1=new Person("Bob","24"); var person2=new Person("Rose","27");
建立Person建構函式的新執行個體,必須使用new操作符。調用建構函式會經曆以下幾個步驟:
- 建立一個新對象;
- 將建構函式的範圍賦給新對象--this就指向新對象;
- 執行建構函式中的代碼;
- 返回新對象;
建構函式模式雖然好用,但也並非沒有缺點。每個執行個體中的方法都是重新建立的,以建構函式模式穿件執行個體會導致不同的範圍鏈和標識符解析。因此,不同執行個體上的同名函數是不相等的。
alert(person1.sayName==person2.sayName) //false
四、原型模式
每一個建立的函數都有一個prototype屬性,指向一個對象,而這個對象的用途是包含了其所有執行個體共用的屬性和方法。因此,我們可以把那些不變的屬性和方法直接定義在prototype對象上。
function Person(name,age){ Person.prototype.name=name; Person.prototype.age=age; Person.prototype.sayName=function(){ alert(this.name); } }
var person1=new Person("Bob","24"); var person2=new Person("Rose","27"); person1.sayName(); //Rose person2.sayName(); //Rose alert(person1.sayName==person2.sayName) //true
有原型模式建立的執行個體的屬性和方法都指向prototype對象。且原型的屬性、方法都是動態,我們對原型對象所做的任何修改都能從執行個體上體現出來,所以person1.sayName()輸出Rose。但是,執行個體一般都是要有屬於自己的全部屬性的,這也是很少有人單獨使用原型模式的原因。
五、組合使用建構函式模式和原型模式
由上可知,建構函式模式可以定義每個執行個體特有的屬性和方法,原型模式定義所有執行個體共用的動態屬性和方法。混成模式可謂是集兩家之所長!
function Person(name,age){ this.name=name; this.age=age; this.sayName=function(){ alert(this.name); } } Person.prototype={ job:"teacher", age:"30", sayAge:function(){ alert(this.age); } }
var person1=new Person("Bob","24"); var person2=new Person("Rose","27"); person1.sayAge(); //24 person2.sayAge(); //37 alert(person1.sayName==person2.sayName); //false alert(person1.sayAge==person2.sayAge); //true
在這個例子中,我們可以把共用的屬性和方法,定義在prototype對象上;特有的屬性、方法定義在執行個體對象上。但是上例中,我們在執行個體和原型中都定義了age屬性,執行個體結果顯示執行個體屬性。若我們將執行個體中的age屬性去掉:
function Person(name,age){ this.name=name; this.sayName=function(){ alert(this.name); } } Person.prototype={ job:"teacher", age:"30", sayAge:function(){ alert(this.age); } }
var person1=new Person("Bob","24"); var person2=new Person("Rose","27"); person1.sayAge(); //30 person2.sayAge(); //30
執行個體結果都返回原型中的屬性值。這是由於當代碼讀取某個對象的某個屬性時,搜尋首先從對象執行個體開始,若執行個體中存在則返回該值且屏蔽掉原型中的同名屬性;若沒找到,則繼續在原型對象中搜尋。
建構函式和原型的混成模式,是目前用來建立自訂類型的一種預設模式!
javascript之建立對象