ES6發(fā)布以來(lái)在塔,給前端開(kāi)發(fā)人員帶了不少的驚喜,它包含了一些很贊的特性拨黔,極大的方便了開(kāi)發(fā)蛔溃,class便是其中之一。在我的工作中篱蝇,也用到了ES6這一新特性贺待,雖然一直在使用,但是并沒(méi)有去認(rèn)真了解過(guò)它零截,于是做了一些功課麸塞,在這里跟大家分享自己的一些心得和看法。
在ES6以前涧衙,JS作為一門非面向?qū)ο蟮恼Z(yǔ)言哪工,并沒(méi)有給我們提供對(duì)類的支持,JS開(kāi)發(fā)者傳統(tǒng)的常用做法是用構(gòu)造函數(shù)來(lái)模擬類的實(shí)現(xiàn)弧哎,通過(guò)將屬性和方法定義在原型上將自身的屬性共享給它的實(shí)例正勒。
一個(gè)用構(gòu)造函數(shù)實(shí)現(xiàn)類的例子:
function Dog(name) {
this.name = name;
}
Dog.prototype.saySomething = function() {
console.log('汪汪汪');
};
var dog = new Dog('LiLy');
dog.name //LiLy
dog.saySomething //汪汪汪
1.class的定義
而ES6引入了class,這個(gè)在面向?qū)ο笳Z(yǔ)言中常見(jiàn)的關(guān)鍵字傻铣,和上面的傳統(tǒng)方法相比有什么不同章贞?這里我先用class的寫(xiě)法將上面的例子改寫(xiě)一下:
class Dog{
constructor(name){
this.name = name;
}
saySomething(){
console.log('汪汪汪');
}
}
var dog = new Dog('LiLy'); //也是通過(guò)new實(shí)例化
dog.name //LiLy
dog.saySomething() //汪汪汪
上面的代碼用class關(guān)鍵字定義了一個(gè)類,這個(gè)類有一個(gè)構(gòu)造函數(shù)constructor非洲,當(dāng)通過(guò)new實(shí)例化一個(gè)對(duì)象時(shí)會(huì)自動(dòng)調(diào)用鸭限。還定義了一個(gè)saySomething方法,該方法不需要添加function也不需要prototype關(guān)鍵字两踏。
我們已經(jīng)知道败京,第一種方法中通過(guò)構(gòu)造函數(shù)創(chuàng)建的類,本質(zhì)是一個(gè)函數(shù)梦染,實(shí)際是將方法添加到了函數(shù)的原型上赡麦,那通過(guò)class定義的類又如何呢,于是我試著做了以下輸出:
typeof Dog // "function"
Dog.prototype.saySomething(); //汪汪汪
Dog.prototype.constructor === Dog //ture
這就表明帕识,class其實(shí)跟構(gòu)造函數(shù)的實(shí)現(xiàn)沒(méi)有什么本質(zhì)的差別泛粹,類本身也是一個(gè)函數(shù),類的所有方法也是定義在prototype上肮疗,類本身指向它的構(gòu)造函數(shù)晶姊,class的實(shí)現(xiàn)還是基于prototype的,它只是把prototype藏起來(lái)了伪货。
不少人管這種寫(xiě)法叫做ES6的語(yǔ)法糖们衙,因?yàn)閏lass的本質(zhì)還是ES5的語(yǔ)法钾怔,但是更加的簡(jiǎn)潔易懂、更加接近面向?qū)ο蟮膶?xiě)法蒙挑。
2.class中的屬性和方法
與面向?qū)ο笳Z(yǔ)言中類不同的是宗侦,ES6的class中只有實(shí)例屬性,無(wú)法定義類成員屬性忆蚀,只能定義方法矾利。
實(shí)例屬性######
在ES6中,類的實(shí)例屬性只能定義在構(gòu)造函數(shù)中蜓谋,用this關(guān)鍵字定義只屬于實(shí)例對(duì)象本身的屬性,實(shí)例之間互不影響炭分。千萬(wàn)不要在類中直接定義成員屬性桃焕,至少目前來(lái)說(shuō)是不支持的。
class Dog{
name = 'LiLy'; //錯(cuò)誤用法捧毛,但ES7已有草案观堂,未來(lái)可能支持這種寫(xiě)法
constructor(name){
this.name = name; //正確
}
說(shuō)到class中的屬性就不得不提面向?qū)ο笳Z(yǔ)言中類的屬性,通常來(lái)說(shuō)呀忧,類的屬性是可以被實(shí)例繼承的师痕,而在class中,如果我們想定義一個(gè)實(shí)例之間共享的屬性而账,那就只能用搬出我們的.prototype把屬性定義到類的原型對(duì)象上胰坟。
Dog.prototype.kind = 'animal'
這么看來(lái)class真是有點(diǎn)雞肋啊,還是有很多事做不了泞辐,要用到prototype才能解決問(wèn)題笔横。
原型方法與靜態(tài)方法######
原型方法能夠被類的實(shí)例繼承,實(shí)例擁有類的一切原型方法咐吼。下面的例子中吹缔,可以直接訪問(wèn)通過(guò)實(shí)例調(diào)用方法saySomething()。
靜態(tài)方法在函數(shù)名稱前添加static關(guān)鍵字锯茄,這一類方法不能被實(shí)例直接調(diào)用厢塘,只能通過(guò)類名稱訪問(wèn)。各位可以參照如下的例子理解一下:
class Dog{
constructor(name){
this.name = name;
}
saySomething(){
console.log('汪汪汪');
}
static sayHello(){
console.log('hello');
}
}
var dog = new Dog('LiLy');
dog.saySomething(); //汪汪汪
Dog.sayHello(); //hello
dog.sayHello(); //dog.sayHello is not a function
3.繼承更加方便
ES6中可以用extend很方便的實(shí)現(xiàn)class之間的繼承肌幽,相比ES5中的繼承讓人愉悅得多晚碾。
class Corgi extends Dog{
constructor(name,age){
super(name);
this.name = 'Tom';
this.age = age;
}
}
var corgi = new Corgi('corgi',2);
corgi.name //Tom
corgi.age // 2,不調(diào)super()則會(huì)因?yàn)檎也坏絫his對(duì)象無(wú)法初始化age的值
corgi.saySomething() //汪汪汪
在這一段代碼中,Corgi類繼承了Dog類喂急,它能夠改寫(xiě)實(shí)例屬性還能調(diào)用父類的方法迄薄。
需要注意的是,子類的構(gòu)造函數(shù)中煮岁,用了super方法調(diào)用父類的構(gòu)造函數(shù)并繼承this對(duì)象讥蔽,再在自己的構(gòu)造函數(shù)中對(duì)this對(duì)象增加屬性和方法涣易。子類不能自己生成this,而super最關(guān)鍵的作用就是生成this對(duì)象冶伞。
4.項(xiàng)目應(yīng)用
在我們金融壹賬通前端H5的項(xiàng)目中新症,將class作為組織頁(yè)面js的一種方式,通常來(lái)說(shuō)响禽,一個(gè)js中包含一個(gè)類的聲明和實(shí)例化徒爹。一個(gè)常見(jiàn)的index.js的結(jié)構(gòu)看起來(lái)會(huì)是這樣子的:
class Index {
constructor() {
this._init();//初始化
this.onBack();//監(jiān)聽(tīng)回調(diào)
this.bindEvent();//事件綁定
//更多代碼
}
_init(){
//代碼塊
}
onBack(){
//代碼塊
}
bindEvent(){
//代碼塊
}
new Index();
這樣組織JS最大的好處便是結(jié)構(gòu)清晰、可讀性強(qiáng)芋类。在構(gòu)造函數(shù)中晰赞,調(diào)用了類中的幾個(gè)方法,這樣一來(lái)疮跑,我們new一個(gè)Index類的時(shí)候以清,會(huì)自動(dòng)運(yùn)行constructor這個(gè)函數(shù),并在里面進(jìn)行初始化贮竟、綁定事件和設(shè)置監(jiān)聽(tīng)等等丽焊。
但是也看到有的同事在constructor函數(shù)中設(shè)置埋點(diǎn)、請(qǐng)求接口咕别、初始化變量等等技健,這種用法雖說(shuō)沒(méi)有什么錯(cuò)誤,但是違背了我們使用class的初衷惰拱,在代碼結(jié)構(gòu)上雌贱,顯得雜亂無(wú)章,不利于閱讀理解偿短。
5.總結(jié)
缺點(diǎn):在JS中帽芽,類是基于原型繼承實(shí)現(xiàn)的,與面向?qū)ο蟮墓δ懿顒e很大翔冀,很多功能在這里都是不支持的导街,比如類屬性、類嵌套纤子、多重繼承等等搬瑰。兩者可以說(shuō)完全不是一個(gè)東西,沒(méi)有什么可比性控硼。
優(yōu)勢(shì):語(yǔ)法更加地簡(jiǎn)潔泽论,不再需要每次都引用prototype去定義類的方法,也方便了編輯器檢查代碼語(yǔ)法卡乾。