本節是第四講的第十四小節,上一節我們為大家介紹了JAVAScript對象的基礎概念,本節為大家介紹JavaScrip面向對象編程(OOP)以及構造函數等概念。
面向對象的程序設計(Object-oriented programming,OOP)
OOP 的基本思想是:在程序里,我們通過使用對象去構建現實世界的模型,把原本很難(或不可)能被使用的功能,簡單化并提供出來,以供訪問。對象可以包含相關的數據和代碼,這些數據和代碼用于表示 你所建造的模型是什么樣子,以及擁有什么樣的行為或功能。對象包(object package,或者叫命名空間 namespace)存儲(官方用語:封裝)著對象的數據(常常還包括函數),使數據的組織和訪問變得更容易了;對象也常用作 數據存儲體(data stores),用于在網絡上運輸數據,十分便捷。
定義一個對象模板(Object template)
讓我們來考慮一個簡單的程序,它可以顯示一個學校的學生和老師的信息.在這里我們不討論任何程序語言,我們只討論 OOP 思想。
首先,我們可以回到上一節拿到定義好屬性和方法的Person對象。對于一個人(person)來說,我們能在他們身上獲取到很多信息(他們的住址,身高,鞋碼,基因圖譜,護照信息,顯著的性格特征等等),然而,我們僅僅需要他們的名字,年齡,性別,興趣 這些信息,然后,我們會基于他們的這些信息寫一個簡短的介紹關于他們自己,在最后我們還需要教會他們打招呼。以上的方式被稱為抽象-為了我們編程的目標而利用事物的一些重要特性去把復雜的事物簡單化。
在一些面向對象的語言中,我們用類(class)的概念去描述一個對象(您在下面就能看到JavaScript使用了一個完全不同的術語)-類并不完全是一個對象,它更像是一個定義對象特質的模板。
創造一個真正的對象
從上面我們創建的class中, 我們能夠基于它創建出一些對象 - 一些擁有class中屬性及方法的對象。基于我們的Person類,我們可以創建出許許多多的真實的人:
當一個對象需要從類中創建出來時,類的構造函數就會運行來創建這個實例。這種創建對象的過程我們稱之為實例化-實例對象被類實例化。
具體的子類
在這個例子里,我們不想要泛指的人,我們想要像老師和學生這樣類型更為具體的人。在 OOP 里,我們可以創建基于其它類的新類,這些新的子類可以繼承它們父類的數據和功能。比起復制來說這樣能夠使用父對象共有的功能。如果類之間的功能不同,你可以根據需要定義專用的特征。
這是非常有用的,老師和學生具有一些相同的特征比如姓名、性別、年齡,因此只需要定義這些特征一次就可以了。您可以在不同的類里分開定義這些相同的特征,這樣該特征會有一個不同的命名空間。比如,一個學生的 greeting 可以是 "Yo, I'm [firstName]" (例子 Yo, I'm Sam),老師的可能會正式一些,比如"Hello, my name is [Prefix] [lastName]" (例子 Hello, My name is Mr Griffiths)。
Note:多態(polymorphism)—這個高大上的詞正是用來描述多個對象擁有實現共同方法的能力。
具體的對象
現在可以根據子類創建對象。
構建函數(Constructor Functions)和對象
有些人認為 JavaScript 不是真正的面向對象的語言,比如它沒有像許多面向對象的語言一樣有用于創建class類的聲明。JavaScript 用一種稱為構建函數(constructor functions)的特殊函數來定義對象和它們的特征。構建函數非常有用,因為很多情況下您不知道實際需要多少個對象(實例)。構建函數提供了創建您所需對象(實例)的有效方法,將對象的數據和特征函數按需聯結至相應對象。
不像“經典”的面向對象的語言,從構建函數創建的新實例的特征并非全盤復制,而是通過一個叫做原形鏈的參考鏈鏈接過去的。所以這并非真正的實例,嚴格的講, JavaScript 在對象間使用和其它語言的共享機制不同。
Note:“經典”的面向對象的語言就像上面提到的,OOP 可能很快就變得非常復雜,JavaScript 找到了在不變的特別復雜的情況下利用面向對象的優點的方法。
一個簡單的例子
function Person(name) {
this.name = name;
this.greeting = function() {
alert('Hi! I'm ' + this.name + '.');
};}
var person1 = new Person('Bob');
var person2 = new Person('Sarah');
person1.name
person1.greeting()
person2.name
person2.greeting()
這個構建函數是 JavaScript 版本的類。您會發現,它只定義了對象的屬性和方法,除了沒有明確創建一個對象和返回任何值和之外,它有了您期待的函數所擁有的全部功能。這里使用了this關鍵詞,即無論是該對象的哪個實例被這個構建函數創建,它的 name 屬性就是傳遞到構建函數形參name的值,它的 greeting() 方法中也將使用相同的傳遞到構建函數形參name的值。
Note: 一個構建函數通常是大寫字母開頭,這樣便于區分構建函數和普通函數。
頁面上有兩個對象,每一個保存在不同的命名空間里,當您訪問它們的屬性和方法時,您需要使用person1或者person2來調用它們。盡管它們有著相同的name屬性和 greeting()方法它們是各自獨立的,所以相互的功能不會沖突。注意它們使用的是自己的 name 值,這也是使用 this 關鍵字的原因,它們使用的從實參傳入形參的自己的值,而不是其它的什么值。
創建最終的構造函數
function Person(first, last,gender) {
this.name = {
'first': first, 'last': last
};
this.gender = gender;
this.greeting = function() {
alert('Hi! I'm ' + this.name.first + '.');
};
}
let person1 = new Person('Bob', 'Smith', 'male');
Object()構造函數
到現在為止,我們了解到了兩種不同的創建對象的方式 —— 聲明一個對象的語法, 與使用構造函數。使用Object()構造函數來創建一個新對象。 是的, 一般對象都有構造函數,它創建了一個空的對象。
常見有兩種創建方式,第一種如下:
var person1 = new Object();
person1.name = 'Chris';
person1['gender'] = 'male';
person1.greeting = function() {
alert('Hi! I'm ' + this.name + '.');
}
還有一種如下:
var person1 = new Object({
name : 'Chris',
gender: 'male',
greeting : function() {
alert('Hi! I'm ' + this.name + '.');
}});
JavaScript有個內嵌的方法create(), 它允許您基于現有對象創建新的對象。person2是基于person1創建的, 它們具有相同的屬性和方法。這非常有用, 因為它允許您創建新的對象而無需定義構造函數。缺點是比起構造函數,瀏覽器在更晚的時候才支持create()方法(IE9, IE8 或甚至以前相比), 加上一些人認為構造函數讓您的代碼看上去更整潔 —— 您可以在一個地方創建您的構造函數, 然后根據需要創建實例, 這讓您能很清楚地知道它們來自哪里。例如:
var person2 = Object.create(person1);
以上內容部分摘自視頻課程04網頁游戲編程JavaScript-14面向對象編程,更多示例請參見網站示例。跟著張員外講編程,學習更輕松,不花錢還能學習真本領。