class 基本語(yǔ)法

1.簡(jiǎn)介

JavaScript 語(yǔ)言中距潘,生成實(shí)例對(duì)象的傳統(tǒng)方法是通過(guò)構(gòu)造函數(shù)稽犁。下面是一個(gè)例子虑椎。


1.jpg

上面這種寫法跟傳統(tǒng)的面向?qū)ο笳Z(yǔ)言(比如 C++ 和 Java)差異很大星虹,很容易讓新學(xué)習(xí)這門語(yǔ)言的程序員感到困惑忽妒。

ES6 提供了更接近傳統(tǒng)語(yǔ)言的寫法,引入了 Class(類)這個(gè)概念喧务,作為對(duì)象的模板。通過(guò)class關(guān)鍵字衡载,可以定義類娜饵。

基本上,ES6 的class可以看作只是一個(gè)語(yǔ)法糖,它的絕大部分功能贷痪,ES5 都可以做到尚镰,新的class寫法只是讓對(duì)象原型的寫法更加清晰、更像面向?qū)ο缶幊痰恼Z(yǔ)法而已唬渗。上面的代碼用 ES6 的class改寫座菠,就是下面這樣降宅。

2.jpg

上面代碼定義了一個(gè)“類”,可以看到里面有一個(gè)constructor方法,這就是構(gòu)造方法,而 this關(guān)鍵字則代表實(shí)例對(duì)象也就是說(shuō)涎拉,ES5 的構(gòu)造函數(shù)Person酪我,對(duì)應(yīng) ES6 的Person類的構(gòu)造方法带饱。

Person類除了構(gòu)造方法教寂,還定義了一個(gè)toString方法轨淌。注意媳拴,定義“類”的方法的時(shí)候僻造,前面不需要加上function這個(gè)關(guān)鍵字,直接把函數(shù)定義放進(jìn)去了就可以了立膛。另外揪罕,方法之間不需要逗號(hào)分隔梯码,加了會(huì)報(bào)錯(cuò)。

上面代碼表明好啰,類的數(shù)據(jù)類型就是函數(shù)轩娶,類本身就指向構(gòu)造函數(shù)。

使用的時(shí)候框往,也是直接對(duì)類使用new命令鳄抒,跟構(gòu)造函數(shù)的用法完全一致。

構(gòu)造函數(shù)的prototype屬性椰弊,在 ES6 的“類”上面繼續(xù)存在许溅。事實(shí)上,類的所有方法都定義在類的prototype屬性上面秉版。

在類的實(shí)例上面調(diào)用方法贤重,其實(shí)就是調(diào)用原型上的方法。

prototype對(duì)象的constructor屬性清焕,直接指向“類”的本身并蝗,這與 ES5 的行為是一致的。

1.jpg

另外耐朴,類的內(nèi)部所有定義的方法借卧,都是不可枚舉的(non-enumerable)。

1.jpg

上面代碼中筛峭,toString方法是Person類內(nèi)部定義的方法铐刘,它是不可枚舉的。這一點(diǎn)與 ES5 的行為不一致影晓。

1.jpg

上面代碼采用 ES5 的寫法镰吵,toString方法就是可枚舉的。




2.嚴(yán)格模式

類和模塊的內(nèi)部挂签,默認(rèn)就是嚴(yán)格模式疤祭,所以不需要使用use strict指定運(yùn)行模式。只要你的代碼寫在類或模塊之中饵婆,就只有嚴(yán)格模式可用勺馆。

考慮到未來(lái)所有的代碼,其實(shí)都是運(yùn)行在模塊之中侨核,所以 ES6 實(shí)際上把整個(gè)語(yǔ)言升級(jí)到了嚴(yán)格模式草穆。



3.constructor 方法

constructor方法是類的默認(rèn)方法,通過(guò)new命令生成對(duì)象實(shí)例時(shí)搓译,自動(dòng)調(diào)用該方法悲柱。

// 定義類

class Person{
    constructor(name,age){
        this.name=name;
        this.age=age;
        console.log(2213)   // 2213
    }
}

let p1=new Person('Andy',31)

可以看到控制臺(tái)打印了2213, 證明通過(guò)new命令生成實(shí)例對(duì)象時(shí),自動(dòng)調(diào)用constructor方法

另外,類里面的this指代的都是實(shí)例對(duì)象,請(qǐng)看下面這個(gè)例子

// 定義類

class Person{
    constructor(name,age){
        this.name=name;
        this.age=age;
    }

    toString(){
        console.log(this) 
    }
}

let p1=new Person('Andy',31)   //  Person {name: "Andy", age: 31}


p1.toString()


一個(gè)類必須有constructor方法些己,如果沒有顯式定義豌鸡,一個(gè)空的constructor方法會(huì)被默認(rèn)添加嘿般。

1.jpg

上面代碼中,定義了一個(gè)空的類Person涯冠,JavaScript 引擎會(huì)自動(dòng)為它添加一個(gè)空的constructor方法炉奴。

constructor方法默認(rèn)返回實(shí)例對(duì)象(即this),完全可以指定返回另外一個(gè)對(duì)象功偿。

1.jpg

上面代碼中盆佣,constructor函數(shù)返回一個(gè)全新的對(duì)象往堡,結(jié)果導(dǎo)致實(shí)例對(duì)象不是Foo類的實(shí)例械荷。

類必須使用new調(diào)用,否則會(huì)報(bào)錯(cuò)虑灰。這是它跟普通構(gòu)造函數(shù)的一個(gè)主要區(qū)別吨瞎,后者不用new也可以執(zhí)行。



4.類的實(shí)例對(duì)象

生成類的實(shí)例對(duì)象的寫法穆咐,與 ES5 完全一樣颤诀,也是使用new命令。

需要注意的是对湃,需要加上new崖叫,如果忘記加上new,像函數(shù)那樣調(diào)用Class拍柒,將會(huì)報(bào)錯(cuò)心傀。

1.jpg

與 ES5 一樣,實(shí)例的屬性除非顯式定義在其本身(即定義在this對(duì)象上)拆讯,否則都是定義在原型上(即定義在class上)脂男。

toString

上面代碼中,定義了一個(gè) Person類,constructor中的sexagenew出來(lái)的實(shí)例對(duì)象的屬性种呐,打印 Person.hasOwnProperty('sex')結(jié)果是false, 打印 p1.hasOwnProperty('sex')結(jié)果是true 宰翅。 這也證明了 constructor中的this指代的是實(shí)例對(duì)象。




與 ES5 一樣爽室,類的所有實(shí)例共享一個(gè)原型對(duì)象汁讼。

1.jpg

上面代碼中,p1和p2都是Person的實(shí)例阔墩,它們的原型都是Person.prototype嘿架,所以 _proto_屬性是相等的。

這也意味著戈擒,可以通過(guò)實(shí)例的_proto_屬性為“類”添加方法眶明。

1.jpg

上面代碼在p1的原型上添加了一個(gè)printName方法,由于p1的原型就是p2的原型筐高,
因此p2也可以調(diào)用這個(gè)方法搜囱。而且丑瞧,此后新建的實(shí)例p3也可以調(diào)用這個(gè)方法。
這意味著蜀肘,使用實(shí)例的_proto
屬性改寫原型绊汹,必須相當(dāng)謹(jǐn)慎,
不推薦使用扮宠,因?yàn)檫@會(huì)改變“類”的原始定義西乖,影響到所有實(shí)例。





5.class表達(dá)式

與函數(shù)一樣坛增,類也可以使用表達(dá)式的形式定義获雕。

const MyClass = class Me {
  getClassName() {
    return Me.name;
  }
};

let inst = new MyClass();
inst.getClassName() // Me
Me.name // ReferenceError: Me is not defined

上面代碼使用表達(dá)式定義了一個(gè)類。

需要注意的是收捣,這個(gè)類的名字是MyClass而不是Me届案,Me只在 Class 的內(nèi)部代碼可用,指代當(dāng)前類罢艾。




6.不存在變量提升

類不存在變量提升(hoist)楣颠,這一點(diǎn)與 ES5 完全不同

new Foo(); // ReferenceError
class Foo {}

上面代碼中,F(xiàn)oo類使用在前咐蚯,定義在后童漩,這樣會(huì)報(bào)錯(cuò),因?yàn)?ES6 不會(huì)把類的聲明提升到代碼頭部春锋。這種規(guī)定的原因與下文要提到的繼承有關(guān)矫膨,必須保證子類在父類之后定義。

{
  let Foo = class {};
  class Bar extends Foo {
  }
}

上面的代碼不會(huì)報(bào)錯(cuò)看疙,因?yàn)锽ar繼承Foo的時(shí)候豆拨,F(xiàn)oo已經(jīng)有定義了。但是能庆,如果存在class的提升施禾,上面代碼就會(huì)報(bào)錯(cuò),因?yàn)閏lass會(huì)被提升到代碼頭部搁胆,而let命令是不提升的弥搞,所以導(dǎo)致Bar繼承Foo的時(shí)候,F(xiàn)oo還沒有定義渠旁。


7.私有方法和私有屬性

私有方法是常見需求攀例,但 ES6 不提供,只能通過(guò)變通方法模擬實(shí)現(xiàn)顾腊。





8.this的指向

類的方法內(nèi)部如果含有this粤铭,它默認(rèn)指向類的實(shí)例。但是杂靶,必須非常小心梆惯,一旦單獨(dú)使用該方法酱鸭,很可能報(bào)錯(cuò)。

1.jpg

上面的例子說(shuō)明垛吗,在單獨(dú)執(zhí)行printName這個(gè)函數(shù)的時(shí)候凹髓,由于this的指向問(wèn)題,函數(shù)中的代碼 this.print()當(dāng)前上下文環(huán)境中找不到print這個(gè)函數(shù)怯屉,所以報(bào)錯(cuò)蔚舀。

一個(gè)比較簡(jiǎn)單的解決方法是,在構(gòu)造方法中綁定this锨络,這樣就不會(huì)找不到print方法了赌躺。

請(qǐng)看下面這個(gè)更為復(fù)雜的情況。

2.jpg

這個(gè)例子中足删,在class Logger的constructor中我們使用了bind方法寿谴,把printName這個(gè)方法的執(zhí)行上下文環(huán)境綁定到了class Logger的實(shí)例上锁右。

bind方法是新創(chuàng)建一個(gè)函數(shù)失受,然后把它的上下文綁定到bind()括號(hào)中的參數(shù)上,然后將它返回咏瑟。

所以拂到,bind后函數(shù)不會(huì)執(zhí)行,而只是返回一個(gè)改變了上下文的函數(shù)副本码泞,而call和apply是直接執(zhí)行函數(shù)兄旬。

后面的代碼中,我們new了一個(gè) Logger的實(shí)例余寥,打印出來(lái)领铐。
發(fā)現(xiàn)實(shí)例中有userName passwords 和 printName三個(gè)屬性,前面兩個(gè)是key value屬性宋舷,最后的一個(gè) printName是Logger實(shí)例的一個(gè)方法绪撵。

通過(guò)var {printName}=logger把printName單獨(dú)拿出來(lái),打印printName發(fā)現(xiàn)它是一個(gè)函數(shù)祝蝠,它是實(shí)例logger的一個(gè)OwenProperty音诈,其原型proto指向Function的prototype屬性。

注意到printName._proto與實(shí)例 logger._proto顯然是不等的绎狭。

它與Function的原型才相等细溅!

前面提到,我們使用bind方法儡嘶,將printName的上下文環(huán)境this改變成了class Logger的實(shí)例對(duì)象上喇聊,所以直接調(diào)用 printName方法可行了,它會(huì)打印出hello lv的信息蹦狂。


關(guān)于bind()函數(shù)

1.jpg

這個(gè)例子中誓篱,我們?cè)赾onstructor中使用了bind方法邻耕,將實(shí)例對(duì)象logger的上下文環(huán)境this綁定到了一個(gè)新的對(duì)象上面,新的對(duì)象上面也有print方法

我們把實(shí)例對(duì)象logger的print方法賦值給printName方法燕鸽,單獨(dú)調(diào)用printName方法時(shí)兄世,發(fā)現(xiàn)打印的都是 敵法師,新的對(duì)象里面的name,sex屬性值啊研。




9.name 屬性

由于本質(zhì)上御滩,ES6 的類只是 ES5 的構(gòu)造函數(shù)的一層包裝,所以函數(shù)的許多特性都被Class繼承党远,包括name屬性削解。

class Point {}
Point.name // "Point"

前面有提到過(guò)。

Person.hasOwnProperty('name');打印的是true沟娱,是因?yàn)榍珊暇褪沁@個(gè)原因氛驮。實(shí)際上打印 Person.hasOwnProperty('age');打印的就是false





10.Class 的取值函數(shù)(getter)和存值函數(shù)(setter)

與 ES5 一樣,在“類”的內(nèi)部可以使用get和set關(guān)鍵字济似,對(duì)某個(gè)屬性設(shè)置存值函數(shù)和取值函數(shù)矫废,攔截該屬性的存取行為。

1.jpg

上面代碼中砰蠢,prop屬性有對(duì)應(yīng)的存值函數(shù)和取值函數(shù)蓖扑,因此賦值和讀取行為都被自定義了。

存值函數(shù)和取值函數(shù)是設(shè)置在屬性的 Descriptor 對(duì)象上的台舱。

12.class的靜態(tài)方法

類相當(dāng)于實(shí)例的原型律杠,所有在類中定義的方法,都會(huì)被實(shí)例繼承竞惋。如果在一個(gè)方法前柜去,加上static關(guān)鍵字,就表示該方法不會(huì)被實(shí)例繼承拆宛,而是直接通過(guò)類來(lái)調(diào)用嗓奢,這就稱為“靜態(tài)方法”。

1.jpg

上面代碼中胰挑,Person類有個(gè)靜態(tài)方法hello(),可以在Person類上調(diào)用蔓罚,但是不能在Person的實(shí)例上調(diào)用。

嘗試 p.hello()是報(bào)錯(cuò)的瞻颂。

注意豺谈,如果靜態(tài)方法包含this關(guān)鍵字,這個(gè)this指的是類贡这,而不是實(shí)例茬末。

1.jpg

上面代碼中,靜態(tài)方法bar調(diào)用了this.baz,這里的this指的是Person類丽惭,而不是Person的實(shí)例击奶,等同于調(diào)用Person.baz。

另外责掏,從這個(gè)例子還可以看出柜砾,靜態(tài)方法可以與非靜態(tài)方法重名。



父類的靜態(tài)方法换衬,可以被子類繼承痰驱。


靜態(tài)方法也是可以從super對(duì)象上調(diào)用的。

1.jpg





13.class的靜態(tài)屬性和實(shí)例屬性

靜態(tài)屬性指的是 Class 本身的屬性瞳浦,即Class.propName担映,而不是定義在實(shí)例對(duì)象(this)上的屬性。

// 定義類

class Person{
    
}

Person.prop=1;

console.log(Person.prop);  //  1

上面的寫法為Person類定義了一個(gè)靜態(tài)屬性prop叫潦。

目前蝇完,只有這種寫法可行,因?yàn)?ES6 明確規(guī)定矗蕊,Class 內(nèi)部只有靜態(tài)方法短蜕,沒有靜態(tài)屬性。

// 以下兩種寫法都無(wú)效
class Person {
  // 寫法一
  prop: 2

  // 寫法二
  static prop: 2
}

Person.prop // undefined
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拔妥,一起剝皮案震驚了整個(gè)濱河市忿危,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌没龙,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缎玫,死亡現(xiàn)場(chǎng)離奇詭異硬纤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)赃磨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門筝家,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人邻辉,你說(shuō)我怎么就攤上這事溪王。” “怎么了值骇?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵莹菱,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我吱瘩,道長(zhǎng)道伟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蜜徽,結(jié)果婚禮上祝懂,老公的妹妹穿的比我還像新娘。我一直安慰自己拘鞋,他們只是感情好砚蓬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著盆色,像睡著了一般怜械。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上傅事,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天缕允,我揣著相機(jī)與錄音,去河邊找鬼蹭越。 笑死障本,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的响鹃。 我是一名探鬼主播驾霜,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼买置!你這毒婦竟也來(lái)了粪糙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤忿项,失蹤者是張志新(化名)和其女友劉穎蓉冈,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轩触,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡寞酿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了脱柱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伐弹。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖榨为,靈堂內(nèi)的尸體忽然破棺而出惨好,到底是詐尸還是另有隱情,我是刑警寧澤随闺,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布日川,位于F島的核電站,受9級(jí)特大地震影響板壮,放射性物質(zhì)發(fā)生泄漏逗鸣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撒璧。 院中可真熱鬧透葛,春花似錦、人聲如沸卿樱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)繁调。三九已至萨蚕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蹄胰,已是汗流浹背岳遥。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留裕寨,地道東北人浩蓉。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像宾袜,于是被迫代替她去往敵國(guó)和親捻艳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • class的基本用法 概述 JavaScript語(yǔ)言的傳統(tǒng)方法是通過(guò)構(gòu)造函數(shù)庆猫,定義并生成新對(duì)象认轨。下面是一個(gè)例子: ...
    呼呼哥閱讀 4,096評(píng)論 3 11
  • 1、引言 JavaScript是一門基于原型繼承的語(yǔ)法月培,ES5中我們實(shí)現(xiàn)面向?qū)ο髽?gòu)造“父類”的寫法一般通過(guò)構(gòu)造函數(shù)...
    七_(dá)五閱讀 158評(píng)論 0 0
  • ??面向?qū)ο螅∣bject-Oriented节视,OO)的語(yǔ)言有一個(gè)標(biāo)志拳锚,那就是它們都有類的概念,而通過(guò)類可以創(chuàng)建任意...
    霜天曉閱讀 2,109評(píng)論 0 6
  • 講解員的講解中寻行,我們了解到東區(qū)自來(lái)水廠的水源是黃河的地表水,流經(jīng)兩條主干道來(lái)到自來(lái)水廠匾荆,首先經(jīng)過(guò)曝氣池除去水中高含...
    emmmmmm哦閱讀 132評(píng)論 0 0
  • 親愛的孩子拌蜘! 此時(shí)此刻,我們每個(gè)人都面對(duì)選擇牙丽!都在檢視著自己简卧!我們?nèi)绾稳ミx擇?我們?yōu)槭裁醋鰶Q定烤芦?我們?cè)鯓拥倪x擇造就...
    論劍閱讀 252評(píng)論 0 0