JavaScript中的類(Class)詳細(xì)介紹
在JavaScript中,可以使用類(Class)來實(shí)現(xiàn)面向?qū)ο缶幊?Object Oriented Programming)。不過,JavaScript中的類與Java中的有所不同,其相應(yīng)的定義和使用也不一樣。
JavaScript中類的定義
在JavaScript中,所有從同一個(gè)原型對(duì)象(prototype)處衍生出來的對(duì)象組成了一個(gè)類;也就是說,JavaScript中的類是一個(gè)對(duì)象集合的概念,如果兩個(gè)對(duì)象它們的prototype相同,那么它們就屬于同一個(gè)類;JavaScript中的類甚至都不需要類名。以下面的代碼為例:
var p = {x:42};
var a = Object.create(p);
var b = Object.create(p);
console.log(a === b);//false
console.log(Object.getPrototypeOf(a) === Object.getPrototypeOf(b));//true
在上述例子中,對(duì)象a和b擁有相同的原型對(duì)象(prototype) p,因此a和b屬于同一個(gè)類(雖然這個(gè)類都沒有類名),它們從原型對(duì)象p處繼承了值為42的屬性x。
從這個(gè)例子中可以看到,原型對(duì)象的作用就相當(dāng)于模板,可以由之衍生/創(chuàng)建出多個(gè)對(duì)象,其地位與Java語言中的類代碼(Class code)相同,是JavaScript中類定義的核心。以下這個(gè)例子中的原型對(duì)象就呈現(xiàn)出更像類代碼的樣子:
var p = {
INCREMENT_BY : 1,
increment : function(x){
return x + this.INCREMENT_BY;
}
}
var a = Object.create(p);
var b = Object.create(p);
console.log(a.increment(7));//8
console.log(b.increment(9));//10
上述例子中,原型對(duì)象p定義了一個(gè)值為1的property (INCREMENT_BY)和一個(gè)名為increment的函數(shù);對(duì)象a和b從p這個(gè)模板處獲取了INCREMENT_BY和increment函數(shù)。當(dāng)調(diào)用對(duì)象a或b的increment函數(shù)時(shí),JavaScript會(huì)試圖獲取a或b的INCREMENT_BY值(this.INCREMENT_BY);由于INCREMENT_BY是從p中獲取的,因此其值都是1 — 從模板中獲取的,值都相同的變量,類似于Java中的靜態(tài)類變量(static variable),因此上面的例子中對(duì)INCREMENT_BY變量命名時(shí)使用了全大寫字符。
在上面的例子中,所有從模板p處創(chuàng)建出來的對(duì)象(屬于同一個(gè)類的這些對(duì)象),其屬性和行為都是一模一樣的。但實(shí)際上對(duì)于同一個(gè)類的不同對(duì)象,它們除了擁有類所定義的屬性/行為以外,往往具有一些自身所特有的屬性與行為。因此,如果需要將prototype這個(gè)模板當(dāng)作類來使用的話,就必須對(duì)每一個(gè)從中衍生出來的對(duì)象進(jìn)行一定的定制:
var p = {
INCREMENT_BY : 1,
increment : function(x){
return x + this.INCREMENT_BY + this.custom_increment_by;
}
}
var a = Object.create(p);
var b = Object.create(p);
a.custom_increment_by = 0;
b.custom_increment_by = 1;
console.log(a.increment(7));//8
console.log(b.increment(9));//11
在這個(gè)例子中,從模板p處創(chuàng)建出來的對(duì)象a和b擁有一個(gè)彼此間值不一定相等的變量custom_increment_by,而它們的increment()函數(shù)這個(gè)行為的最終結(jié)果則與custom_increment_by的值相關(guān)。一般來說,對(duì)新建對(duì)象進(jìn)行定制化的工作往往放在統(tǒng)一的函數(shù)中進(jìn)行:
var p = {
INCREMENT_BY : 1,
increment : function(x){
return x + this.INCREMENT_BY + this.custom_increment_by;
}
}
function getIncrementalClassObject(customIncrementByValue){
var incrementalObj = Object.create(p);
incrementalObj.custom_increment_by = customIncrementByValue;
return incrementalObj;
}
var a = getIncrementalClassObject(0);
var b = getIncrementalClassObject(1);
console.log(a.increment(7));//8
console.log(b.increment(9));//11
如此,便通過原型對(duì)象p和getIncrementalClassObject()函數(shù)完成了一個(gè)類的定義:可以通過調(diào)用getIncrementalClassObject()函數(shù)來獲取原型對(duì)象都是p的對(duì)象,而在調(diào)用getIncrementalClassObject()函數(shù)過程中可以對(duì)這些新建對(duì)象進(jìn)行一定的定制化。值得注意的是,此時(shí)這個(gè)已經(jīng)定義了的類還沒有類名,為了方便描述,姑且稱之為Incremental。
回顧getIncrementalClassObject()函數(shù)中所做的工作,可以看到從Incremental這個(gè)類中創(chuàng)建新的對(duì)象所經(jīng)歷的過程如下:
1.創(chuàng)建一個(gè)空對(duì)象,并將其原型對(duì)象定義為p。
2.根據(jù)不同的參數(shù)值,對(duì)這個(gè)新建的空對(duì)象進(jìn)行定制。
3.返回已經(jīng)定制完成的新對(duì)象。
在JavaScript中,可以通過使用Constructor(構(gòu)造函數(shù))來快速地完成類的定義以及新對(duì)象的創(chuàng)建。
JavaScript中的Constructor(構(gòu)造函數(shù))
從上述Incremental類這個(gè)例子中可以看到,定義新的類需要兩部分代碼:創(chuàng)建原型對(duì)象作為模板、創(chuàng)建自定義函數(shù)對(duì)新對(duì)象進(jìn)行初始化;而從類中創(chuàng)建新的對(duì)象則經(jīng)歷了三個(gè)過程:指定新對(duì)象的原型對(duì)象、定制/初始化新對(duì)象、返回這個(gè)新對(duì)象。在JavaScript中,這一切都可以通過Constructor(構(gòu)造函數(shù))來完成。
JavaScript中的Constructor是一個(gè)函數(shù)(function),承擔(dān)對(duì)新對(duì)象進(jìn)行初始化的職責(zé);而這個(gè)Constructor函數(shù)的prototype則作為模板用于創(chuàng)建新對(duì)象。仍以上述Incremental類為例,用Constructor來重寫代碼后是這樣的:
function Incremental(customIncrementByValue){
this.custom_increment_by = customIncrementByValue;
}
Incremental.prototype = {
INCREMENT_BY : 1,
increment : function(x){
return x + this.INCREMENT_BY + this.custom_increment_by;
}
}
var a = new Incremental(0);
var b = new Incremental(1);
console.log(a.increment(7));//8
console.log(b.increment(9));//11
通過new關(guān)鍵詞,使用Constructor函數(shù)來創(chuàng)建新對(duì)象這一過程,其實(shí)際上經(jīng)歷了以下幾個(gè)階段:
創(chuàng)建一個(gè)新的空對(duì)象。
1.將這個(gè)對(duì)象的原型對(duì)象指向constructor函數(shù)的prototype屬性。
2.將這個(gè)對(duì)象作為this參數(shù),執(zhí)行constructor函數(shù)。
3.這與之前的getIncrementalClassObject()函數(shù)中所做的工作是一樣的。
類名
在使用Constructor創(chuàng)建對(duì)象時(shí),相應(yīng)的對(duì)象也就有了“類名”,這可以從instanceof操作符的結(jié)果上得到驗(yàn)證:
console.log(a instanceof Incremental);//true
console.log(b instanceof Incremental);//true
不過,instanceof操作符并不判斷對(duì)象是否由Incremental這一構(gòu)造函數(shù)所創(chuàng)建,instanceof操作符只判斷對(duì)象的原型對(duì)象是否為Incremental.prototype。當(dāng)存在兩個(gè)prototype一樣的構(gòu)造函數(shù)時(shí),instanceof操作符將統(tǒng)一返回true,而不會(huì)區(qū)分用于創(chuàng)建對(duì)象的構(gòu)造函數(shù)到底是哪個(gè)。
function Incremental2(customIncrementByValue){
this.custom_increment_by = customIncrementByValue + 3;
}
Incremental2.prototype = Incremental.prototype;
console.log(a instanceof Incremental2);//true
相關(guān)文章
JS判斷鼠標(biāo)從什么方向進(jìn)入一個(gè)容器實(shí)例說明
偶然將想到的一個(gè)如何判斷鼠標(biāo)從哪個(gè)方向進(jìn)入一個(gè)容器的問題,并且做了一系列的設(shè)想,代碼部分不是很多,我直接寫了個(gè)示例, 感興趣的朋友可以了解下,或許本文對(duì)你有所幫助2013-02-02
30個(gè)高逼格代碼的JavaScript高級(jí)單行代碼
這篇文章中列出了一個(gè)系列的 30 個(gè) JavaScript 單行代碼,它們?cè)谑褂?nbsp;vanilla js(≥ ES6)進(jìn)行開發(fā)時(shí)非常有用,它們也是使用該語言在最新版本中為我們提供的所有功能來解決問題的優(yōu)雅方式,將它們分為以下5大類:日期、字符串、數(shù)字、數(shù)組、工具2023-08-08
js+canvas實(shí)現(xiàn)繪制正方形并插入文字效果(居中顯示)
canvas是一個(gè)可以讓我們使用腳本繪圖的標(biāo)簽,它提供了一系列完整的屬性和方法,下面這篇文章主要給大家介紹了js+canvas實(shí)現(xiàn)繪制正方形并插入文字居中顯示效果的相關(guān)資料,需要的朋友可以參考下2023-11-11
JS計(jì)算兩個(gè)時(shí)間相差分鐘數(shù)的方法示例
這篇文章主要介紹了JS計(jì)算兩個(gè)時(shí)間相差分鐘數(shù)的方法,結(jié)合完整實(shí)例形式分析了javascript針對(duì)日期時(shí)間的轉(zhuǎn)換與計(jì)算相關(guān)操作技巧,需要的朋友可以參考下2018-01-01
JavaScript的9種繼承實(shí)現(xiàn)方式歸納
這篇文章主要介紹了JavaScript的9種繼承實(shí)現(xiàn)方式歸納,本文講解了原型鏈繼承、原型繼承(非原型鏈)、臨時(shí)構(gòu)造器繼承、屬性拷貝、對(duì)象間繼承等繼承方式,需要的朋友可以參考下2015-05-05
Bootstrap CSS組件之分頁(pagination)和翻頁(pager)
這篇文章主要介為大家詳細(xì)紹了Bootstrap CSS組件之分頁和翻頁的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12
值得分享和收藏的Bootstrap學(xué)習(xí)教程
這絕對(duì)是一套值得分享和大家收藏的Bootstrap學(xué)習(xí)教程,完整的知識(shí)體系,系統(tǒng)的學(xué)習(xí)資料,幫助大家開啟Bootstrap學(xué)習(xí)之旅,享受Bootstrap帶給大家的奇妙樂趣2016-05-05

