在學物件導向(objetct-oriented,oo)程式設計之前,首先需要知道什麼是對象,##ECMA-262,將物件定義為「無序屬性的集合,其屬性可以包含基本值、物件或是函數」。 JavaScript中有多種方式可以建立對象,例如:工廠模式、建構函式模式、原型模式、組合建構函式模式和原型模式、寄生建構函式模式等等。
一、工廠模式工廠模式是軟體工程領域一種廣為人知的設計模式,這種模式抽象化了創建具體物件的過程。考慮到在ECMAScript 中無法創建類別,開發人員發明了一種函數,用函數來封裝以特定介面創建物件的細節。
function createStudent(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var student1= createStudent("xiaoming", 9, "student"); var student2 = createStudent("xiaowagn", 15, "student");函數createStudent()能夠根據接受的參數建立一個包含所有必要資訊的Student物件。可以無數次地呼叫這個函,而每次它都會傳回一個包含三個屬性一個方法的物件。工廠模式雖然解決了創建多個相似物件的問題,但卻
沒有解決物件識別的問題(即如何知道一個物件的類型)。隨著JavaScript的發展,另一個新模式出現了。
二、建構函數模式首先我們將前面的程式碼修改如下:function Student(name,age){ this.name=name; this.age=age; this.showname=function(){ alert(this.name); } } var xiaoming =new Student("xiaoming",6); var xiaogang =new Student("xiaogang",7);與工廠模式區別: 1.
沒有顯示建立物件
2.直接將屬性賦值給了this物件
3.沒有Return語句。
要建立一個實例,需要使用new操作符。
建立物件步驟:1.建立一個新的物件
2.將建構子的作用域賦給新的物件(this就指向這個新的物件)
3.執行建構子的程式碼,為這個物件新增屬性
4.傳回這個物件
alert(xiaoming.constructor==Student) //true;物件的
constructor屬性原本是用來識別一個物件的類型的。檢查一個物件類型,還是使用instanceof
alert(xiaoming instanceof Student) //true alert(xiaoming instanceof Object) //true是因为所有对象均继承自Object
#建立自訂的建構子意味著將來可以將它的實例標識為特定的類型;而這正是建構函數模式勝過工廠模式的地方。使用構造函數也是有缺點的。
就是每個方法都要在每個實例上重新建立一遍。 例如,xiaoming和xiaogang都有一個showname()方法。但是那兩個方法不是同一個Function的實例。 ECMAScript中的函數是對象,因此,每定義一個函數,就是實例化了一個物件。從邏輯角度講,此時建構函數也可以這樣定義。
function student(name,age){ this.name=name; this.showName=new Function(“alert(this.name)”); }可以看出,每個
Student實例都包含一個不同的Function 實例。不同的實例上的同名函數是不相等的。以下程式碼可以證明這一點。
alert(xiaoming.showName==xiaogang.showname);//false二、建構函式模式我們建立的每個函式都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個物件的用途是包含可以由特定類型的所有實例共享的屬性和方法。如果按照字面意思來理解,那麼prototype 就是透過呼叫建構函數而創建的那個物件實例的原型物件。使用原型物件的好處是可以讓所有物件實例共享它所包含的屬性和方法。換句話說,不必在建構函式中定義物件實例的訊息,而是可以將這些資訊直接加入原型物件中。
function Student(){ } Student.property.name=”default name”; Student.property.age=0; Student.property.showName=funciton(){ alert(this.name); } Var xiaoming=new Student(); Var xiaogang=new Student();
与构造函数模式的不同时,新对象的这些属性和方法是由所有的实例共享的。换句话说xiaoming和xiaogang访问的都是同一组属性和同一个showName()函数。要理解原型模式的工作原理,必须先理解ECMAScript 中原型对象的性质。
1. 理解原型对象
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype
属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor
(构造函数)属性,这个属性包含一个指向prototype 属性所在函数的指针。就拿前面的例子来说,
Student.prototype. constructor 指向Student。而通过这个构造函数,我们还可继续为原型对象添加其他属性和方法.
在JS中我们通过isPropertyOf()来判断,某个实例是否指向某个函数的的原型。
Eg:
Student.property.isPropertyOf(xiaoming);//true。
在ECMAScript5中含增加了Object.getPropertyOf()方法来获取一个实例的原型
Eg:
alert(Object.getPropertyOf(xiaoming)==Student.property);//true alert(Object.getPropertyOf(xiaoming).name);//default name
此外,我们还可以通过hasOwnProperty()方法来检测一个属性是存在实例中还是存在原型中。alert(xiaoming.hasOwnProperty(“name”));//false
alert(xiaoming.property.hasOwnProperty(“name”));//true
原型模式也不是没有缺点。首先,它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值。虽然这会在某种程度上带来一些不方便,但还不是原型的最大问题。原型模式的最大问题是由其共享的本性所导致的。原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性倒
也说得过去,毕竟(如前面的例子所示),通过在实例上添加一个同名属性,可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性来说,问题就比较突出.
创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参数;可谓是集两种模式之长。
function Student(name,age){ this.name=name; this.age=age; } Student.property.showName=funciton(){alert(this.name);}
这种构造函数与原型混成的模式,是目前在ECMAScript 中使用最广泛、认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。
通常,在前述的几种模式都不适用的情况下,可以使用寄生(parasitic)构造函数模式。这种模式的基本思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后再返回新创建的对象;但从表面上看,这个函数又很像是典型的构造函数。
funciton Student(name,age){ Var o=new Object(); o.name=name; o.age=age; o.showName=function(){alert(this.name);} Reurn o; }
关于寄生构造函数模式,有一点需要说明:首先,返回的对象与构造函数或者与构造函数的原型属性之间没有关系;也就是说,构造函数返回的对象与在构造函数外部创建的对象没有什么不同。为此,不能依赖instanceof 操作符来确定对象类型。由于存在上述问题,我们建议在可以使用其他模式的情况下,不要使用这种模式。个人感觉这模式还是有点模仿工厂模式。
以上就是JavaScript面向对象编程(对象创建)的内容,更多相关内容请关注PHP中文网(www.php.cn)!