先決條件: | 基本的計算機(jī)素養(yǎng),對HTML和CSS的基本了解,熟悉JavaScript基礎(chǔ)知識(請參見第一步和構(gòu)建塊 / a>)和OOJS基礎(chǔ)知識(請參見對象簡介)。 |
---|---|
目的: | 要理解面向?qū)ο缶幊瘫澈蟮幕纠碚摚@是如何與JavaScript(“一切都是一個對象")有關(guān),以及如何創(chuàng)建構(gòu)造函數(shù)和對象實例。 |
首先,讓我們給出一個簡單的,高級的面向?qū)ο缶幊?OOP)的視圖。 我們說簡單,因為OOP可以很快變得非常復(fù)雜,現(xiàn)在給它一個完全的治療可能會混淆更多的幫助。 OOP的基本思想是,我們使用對象來模擬我們想要在程序中表示的現(xiàn)實世界中的事物,和/或提供一種簡單的方法來訪問否則難以或不可能使用的功能。
對象可以包含相關(guān)數(shù)據(jù)和代碼,它們表示有關(guān)您嘗試建模的信息,以及您希望它具有的功能或行為。 對象數(shù)據(jù)(通常也是函數(shù))可以在一個對象包(它可以被給定一個特定的名稱來引用,有時稱為)中整齊地存儲(官方單詞封裝 > namespace ),使其易于構(gòu)造和訪問; 對象也通常用作可以容易地通過網(wǎng)絡(luò)發(fā)送的數(shù)據(jù)存儲。
讓我們考慮一個簡單的程序,顯示學(xué)校的學(xué)生和教師的信息。 這里我們將一般來看看OOP理論,而不是在任何特定的編程語言的上下文中。
要開始此操作,我們可以從第一個對象文章返回到我們的Person對象類型,該文章定義了人員的通用數(shù)據(jù)和功能。 有很多東西你可以知道一個人(他們的地址,身高,鞋碼,DNA個人資料,護(hù)照號碼,重要的個性特征...),但在這種情況下,我們只感興趣 顯示他們的名字,年齡,性別和興趣,我們也希望能夠基于這些數(shù)據(jù)寫一個簡短的介紹,并讓他們打招呼。 這被稱為抽象 - 創(chuàng)建一個更復(fù)雜的事情的簡單模型,它以一種很容易與我們程序的目的一起使用的方式表示其最重要的方面。
>
在一些OOP語言中,這個通用對象類型定義被稱為類(JavaScript使用不同的機(jī)制和術(shù)語,如下所示) - 它實際上不是對象,而是一個 模板,定義對象應(yīng)具有的特性。
從我們的類中,我們可以創(chuàng)建對象實例 - 包含類中定義的數(shù)據(jù)和功能的對象。 從我們的Person類,我們現(xiàn)在可以創(chuàng)建一些實際的人:
:700px;">
當(dāng)從類創(chuàng)建對象實例時,將運(yùn)行類的構(gòu)造函數(shù)來創(chuàng)建它。 從類創(chuàng)建對象實例的過程稱為實例化 - 對象實例從類中實例化。
在這種情況下,我們不想要一般人 - 我們希望教師和學(xué)生,這兩種更具體類型的人。 在OOP中,我們可以基于其他類創(chuàng)建新類 - 這些新的子類可用于繼承其父類的數(shù)據(jù)和代碼功能 strong>,因此您可以重用所有對象類型通用的功能,而不必重復(fù)它。 在類之間的功能不同時,您可以根據(jù)需要直接在其上定義特定功能。
:700px;">
這是非常有用的 - 教師和學(xué)生分享了許多常見的功能,如姓名,性別和年齡,所以只需要定義這些功能一次便利。 您還可以在不同的類中單獨定義相同的功能,因為該功能的每個定義都將位于不同的命名空間中。 例如,學(xué)生的問候語可以是"Yo,I\'m [firstName]"(例如,
注意:對于多個對象類型實現(xiàn)相同功能的能力而言,多態(tài)性非常奇怪。 以防萬一你想知道。
現(xiàn)在可以從子類創(chuàng)建對象實例。 例如:
; width:700px;">
在本文的其余部分,我們將開始研究如何在JavaScript中實現(xiàn)OOP理論。
有些人認(rèn)為JavaScript不是一個真正的面向?qū)ο蟮恼Z言 - 例如它沒有用于創(chuàng)建像許多OO語言的類的 class
語句。 JavaScript使用稱為構(gòu)造函數(shù)的特殊函數(shù)來定義對象及其特征。 它們很有用,因為你會經(jīng)常遇到你不知道你將要創(chuàng)建多少對象的情況; 構(gòu)造函數(shù)提供了以有效方式創(chuàng)建任意數(shù)量對象的方法,根據(jù)需要將數(shù)據(jù)和函數(shù)附加到它們。
當(dāng)從構(gòu)造函數(shù)創(chuàng)建一個新的對象實例時,并不是所有的功能都被復(fù)制到像"經(jīng)典"OO語言這樣的新對象,而是通過一個稱為原型鏈的引用鏈鏈接到該對象實例(參見 "/ webstart / Objects / Object_prototypes">對象原型)。 所以這不是真正的實例化,嚴(yán)格來說 - JavaScript使用不同的機(jī)制在對象之間共享功能。
注意:不是"經(jīng)典OOP"不一定是壞事; 如上所述,OOP可以非??焖俚氐玫椒浅?fù)雜,JavaScript有一些不錯的方法利用OO功能,而不必太深入。
讓我們探索通過構(gòu)造函數(shù)創(chuàng)建類并在JavaScript中從中創(chuàng)建對象實例。 首先,我們希望您創(chuàng)建一個新的本地副本 class ="external"> oojs.html 文件,我們在第一篇Objects文章中看到。
function createNewPerson(name) { var obj = {}; obj.name = name; obj.greeting = function () { alert('Hi! I\'m ' + this.name + '.'); } return obj; }
var salva = createNewPerson('salva'); salva.name; salva.greeting();This works well enough, but it is a bit longwinded; if we know we want to create an object, why do we need to explicitly create a new empty object and return it? Fortunately JavaScript provides us with a handy shortcut, in the form of constructor functions — let's make one now!
function Person(name) { this.name = name; this.greeting = function() { alert('Hi! I\'m ' + this.name + '.'); }; }
構(gòu)造函數(shù)是JavaScript的一個類的版本。 你會注意到它有一個所有的功能,你期望在一個函數(shù),雖然它不返回任何東西或顯式創(chuàng)建一個對象 - 它基本上只是定義屬性和方法。 你會看到這里使用的 this
關(guān)鍵字 - 它基本上是說,無論何時創(chuàng)建這些對象實例之一,對象的 name
屬性將等于 傳遞給構(gòu)造函數(shù)調(diào)用的名稱值, greeting()
方法將使用傳遞給構(gòu)造函數(shù)調(diào)用的名稱值。
注意:構(gòu)造函數(shù)名稱通常以大寫字母開頭 - 此約定用于使構(gòu)造函數(shù)在代碼中更易于識別。
那么我們?nèi)绾握{(diào)用構(gòu)造函數(shù)來創(chuàng)建一些對象呢?
var person1 = new Person('Bob'); var person2 = new Person('Sarah');
person1.name person1.greeting() person2.name person2.greeting()
涼! 現(xiàn)在,您將看到頁面上有兩個新對象,每個對象都存儲在不同的命名空間下 - 當(dāng)您訪問其屬性和方法時,必須使用 person1
或 > person2
; 他們整齊地打包,使他們不會與其他功能沖突。 但是它們具有相同的 name
屬性和 greeting()
方法。 注意,他們使用自己創(chuàng)建時分配給他們的 name
值; 這是為什么使用 this
非常重要的一個原因,所以他們將使用自己的值,而不是一些其他值。
讓我們再看看構(gòu)造函數(shù)調(diào)用:
var person1 = new Person('Bob'); var person2 = new Person('Sarah');
在每種情況下, new
關(guān)鍵字用于告訴瀏覽器我們要創(chuàng)建一個新的對象實例,后面跟著括號中包含其必需參數(shù)的函數(shù)名稱,結(jié)果存儲在變量中 - 非常類似于如何調(diào)用標(biāo)準(zhǔn)函數(shù)。 每個實例根據(jù)此定義創(chuàng)建:
function Person(name) { this.name = name; this.greeting = function() { alert('Hi! I\'m ' + this.name + '.'); }; }
創(chuàng)建新對象后, person1
和 person2
變量實際上包含以下對象:
{ name : 'Bob', greeting : function() { alert('Hi! I\'m ' + this.name + '.'); } } { name : 'Sarah', greeting : function() { alert('Hi! I\'m ' + this.name + '.'); } }
我們有效地說,因為實際上,功能仍然在類中定義,而不是在對象實例,而不是我們前面看到的對象字面量。
我們上面看到的例子只是一個簡單的例子,讓我們開始。 讓我們開始創(chuàng)建我們的最終 Person()
構(gòu)造函數(shù)。
function Person(first, last, age, gender, interests) { this.name = { first, last }; this.age = age; this.gender = gender; this.interests = interests; this.bio = function() { alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); }; this.greeting = function() { alert('Hi! I\'m ' + this.name.first + '.'); }; };
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
現(xiàn)在您將看到,您可以像訪問我們定義的第一個對象一樣訪問屬性和方法:
person1['age'] person1.interests[1] person1.bio() // etc.
注意:如果您無法使用此工具,請嘗試將您的代碼與我們的版本進(jìn)行比較 - 請參閱 /javascript/oojs/introduction/oojs-class-finished.html"class ="external"> oojs-class-finished.html (也 -area / javascript / oojs / introduction / oojs-class-finished.html"class ="external">查看它正在運(yùn)行)。
首先,嘗試添加一些您自己的對象創(chuàng)建行,并嘗試獲取和設(shè)置生成的對象實例的成員。
此外,我們的 bio()
方法有一些問題 - 輸出總是包括代詞"He",即使你的人是女性,或一些其他首選的性別分類。 并且bio將只包括兩個興趣,即使更多的興趣列在 interests
數(shù)組。 你能解決如何解決這個在類定義(構(gòu)造函數(shù))? 你可以把任何你喜歡的代碼放在構(gòu)造函數(shù)中(你可能需要一些條件和循環(huán))。 考慮如何根據(jù)性別,以及取決于所列出的興趣的數(shù)量是1,2還是多于2,句子應(yīng)該結(jié)構(gòu)不同。
注意:如果您遇到困難,我們提供了 -further-exercises.html"class ="external"> answer在我們的GitHub repo ( class-further-exercises.html"class ="external">看到它現(xiàn)場) - 嘗試自己首先寫它!
到目前為止,我們已經(jīng)看到了兩種創(chuàng)建對象實例的方法 - 聲明對象字面值,并使用構(gòu)造函數(shù)(參見上文)。
這些都是有意義的,但還有其他方法 - 我們希望讓您熟悉這些,以防萬一您在網(wǎng)絡(luò)上的旅行中遇到它們。
首先,您可以使用 Object()
構(gòu)造函數(shù)創(chuàng)建一個新對象。 是的,即使通用對象有一個構(gòu)造函數(shù),它生成一個空對象。
var person1 = new Object();
person1
variable. You can then add properties and methods to this object using dot or bracket notation as desired; try these examples: person1.name = 'Chris'; person1['age'] = 38; person1.greeting = function() { alert('Hi! I\'m ' + this.name + '.'); }
Object()
constructor as a parameter, to prefill it with properties/methods. Try this: var person1 = new Object({ name : 'Chris', age : 38, greeting : function() { alert('Hi! I\'m ' + this.name + '.'); } });
JavaScript有一個內(nèi)置的方法 create()
a> ,它允許您基于現(xiàn)有對象創(chuàng)建新的對象實例。
var person2 = Object.create(person1);
person2.name person2.greeting()
您將看到基于 person1
創(chuàng)建的 person2
- 它具有相同的屬性和方法。 這是非常有用的,因為它允許你創(chuàng)建新的對象實例,而不需要定義一個構(gòu)造函數(shù)。 缺點是 create()
不支持的瀏覽器早在構(gòu)造函數(shù)(IE9,而不是IE8甚至之前),加上一些think構(gòu)造函數(shù)給你的代碼更多的順序 - 你可以創(chuàng)建你的 構(gòu)造函數(shù)在一個地方,然后根據(jù)需要創(chuàng)建實例,并清楚它們來自哪里。
但是,如果你不太擔(dān)心支持真正舊的瀏覽器,并且你只需要一個對象的幾個副本,創(chuàng)建一個構(gòu)造函數(shù)可能是overkill的代碼。 這取決于你喜歡什么。 有些人只是發(fā)現(xiàn) create()
更容易理解和使用。
我們將在后面更詳細(xì)地探討 create()
的效果。
本文提供了面向?qū)ο罄碚摰暮喕晥D - 這不是全部的故事,但它給了我們在這里處理我們的想法。 此外,我們已經(jīng)開始看看JavaScript如何與"經(jīng)典OOP",如何使用構(gòu)造函數(shù)在JavaScript中實現(xiàn)類以及生成對象實例的不同方式有所不同。
在下一篇文章中,我們將探討JavaScript對象原型。
更多建議: