這次我們深入的學習一下JavaScript物件導向技術,在學習之前,必要的說明一下一些物件導向的一些術語。這也是所有面對對象語言所擁有的共同點。有這樣幾個物件導向術語:
一、對象
ECMA-262把物件(object)定義為「屬性的無序集合,每個屬性存放一個原始值、物件或函數」。嚴格來說,這意味著物件是無特定順序的值的陣列。儘管ECMAScript如此定義對象,但它更通用的定義是基於代碼的名詞(人、地點或事物)的表示。
二、類
每個物件都由類別定義,可將類別視為物件的配方。類別不僅要定義物件的介面(interface)(開發者存取的屬性和方法),還要定義物件的內部工作(使屬性和方法發揮作用的程式碼)。編譯器和解釋程式都根據類別的說明建構物件。
三、實例
程式使用類別建立物件時,產生的物件叫作類別的實例(instance)。對類別產生的物件的數量的唯一限制來自於運行程式碼的機器的物理記憶體。每個實例的行為相同,但實例處理一組獨立的資料。由類別建立物件實例的過程叫做實例化(instantiation)。
在前面的章節我們提到過,ECMAScript並沒有正式的類別。相反,ECMA-262把物件定義描述為物件的配方。這是 ECMAScript邏輯上的一種折衷方案,因為物件定義實際上是物件本身。即使類別並不真正存在,我們也把物件定義叫做類,因為大多數開發者對此術語更熟悉,而且從功能上說,兩者是等價的。
使用預設物件只是物件導向語言的能力的一部分,它真正強大之處在於能夠創造自己專用的物件。 ECMAScript 擁有許多建立物件的方法。
1、原始方式
因為物件的屬性可以在物件建立後動態定義,所有許多開發者都在JavaScript 最初引入時編寫類似下面的程式碼:
var Car = new Object(); Car.color = "blue"; Car.doors = 4; Car.mpg = 25; Car.showColor = function() { return this.color; }; document.write(Car.showColor());//输出:blue
在上方的程式碼中,建立物件Car。然後給它設置幾個屬性:它的顏色是藍色,有四個門,每加侖油可以跑 25 英里。最後一個屬性其實是指向函數的指針,這意味著該屬性是個方法。執行這段程式碼後,就可以使用物件Car。不過這裡有一個問題,就是可能需要創建多個Car的實例,這樣就造成了我們會重複許多類似的程式碼,這樣會很麻煩。
2、工廠方式
要解決上述的多個類似物件聲明的問題,開發者創造了能創造並返回特定類型的物件的工廠方式。這種方式就是為了解決實例化物件產生大量重複的問題。
(1)無參數的工廠方式
例如,函數createCar()可用來封裝前面所列的建立Car物件的操作:
function createCar() { var TempCar = new Object(); TempCar.color = "blue"; TempCar.doors = 4; TempCar.mpg = 25; TempCar.showColor = function() { return this.color; }; return TempCar; }; var Car1 = createCar(); var Car2 = createCar(); document.write(Car1.showColor()+"<br/>");//输出:blue document.write(Car2.showColor());//输出:blue
在這裡,第一個範例中的所有程式碼都包含在createCar()函數中。此外,還有一行額外的程式碼,傳回TempCar 物件作為函數值。呼叫此函數,將建立新對象,並賦予它所有必要的屬性,複製出一個我們在前面說明過的Car對象。因此,透過這種方法,我們可以輕鬆地建立Car物件的兩個版本(Car1和 Car2),它們的屬性完全一樣。
(2)有參數的工廠方式
我們也可以修改createCar()函數,給它傳遞各個屬性的預設值,而不是單純地賦予屬性預設值:
function createCar(Color,Doors,Mpg) { var TempCar = new Object(); TempCar.color = Color; TempCar.doors = Doors; TempCar.mpg = Mpg; TempCar.showColor = function() { return this.color; }; return TempCar; }; var Car1 = createCar("red",4,23); var Car2 = createCar("blue",3,25); document.write(Car1.showColor()+"<br/>");//输出:red document.write(Car2.showColor());//输出:blue
將createCar()函數加上參數,即可為要建立的Car物件的color、doors 和mpg屬性賦值。這使得兩個物件具有相同的屬性,卻有不同的屬性值。
工廠方式解決了重複實例化的問題,但是還是有一個問題,那就是前面的例子中,每次呼叫函數createCar(),都要建立新函數showColor(),這意味著每個物件都有自己的showColor () 版本。而事實上,每個物件都共享同一個函數。有些開發者在工廠函數外定義物件的方法,然後透過屬性指向該方法,從而避免這個問題:
function showColor() { return this.color; }; function createCar(Color,Doors,Mpg) { var TempCar = new Object(); TempCar.color = Color; TempCar.doors = Doors; TempCar.mpg = Mpg; TempCar.showColor = showColor; return TempCar; }; var Car1 = createCar("red",4,23); var Car2 = createCar("blue",3,25); document.write(Car1.showColor()+"<br/>");//输出:red document.write(Car2.showColor());//输出:blue
在上面这段重写的代码中,在函数 createCar()之前定义了函数 showColor()。在createCar()内部,赋予对象一个指向已经存在的 showColor() 函数的指针。从功能上讲,这样解决了重复创建函数对象的问题;但是从语义上讲,该函数不太像是对象的方法。所有这些问题都引发了开发者定义的构造函数的出现。
3、构造函数方式
创建构造函数就像创建工厂方式的函数一样容易。第一步选择构造函数的名字。根据惯例,这个名字的首字母大写,以使它与首字母通常是小写的变量名分开。除了这点不同,构造函数看起来很像工厂方式的函数。请看下面的例子:
function Car(Color,Doors,Mpg) { this.color = Color; this.doors = Doors; this.mpg = Mpg; this.showColor = function() { return this.color; }; }; var Car1 = new Car("red",4,23); var Car2 = new Car("blue",3,25); document.write(Car1.showColor()+"<br/>");//输出:red document.write(Car2.showColor());//输出:blue
下面为您解释上面的代码与工厂方式的差别。首先在构造函数内没有创建对象,而是使用this关键字。使用new运算符构造函数时,在执行第一行代码前先创建一个对象,只有用this才能访问该对象。然后可以直接赋予this属性,默认情况下是构造函数的返回值(不必明确使用 return 运算符)。现在,用new运算符和对象名Car创建对象,就更像 ECMAScript 中一般对象的创建方式了。
就像工厂方式的函数,构造函数会重复生成函数,为每个对象都创建独立的函数版本。不过,与工厂方式的函数相似,也可以用外部函数重写构造函数,同样地,这么做语义上无任何意义。这正是下面要讲的原型方式的优势所在。在下篇文章中会详细的分析面向对象的原型方式以及其他综合的方式。
以上就是本文的全部内容,希望对大家的学习javascript程序设计有所帮助。