class類與繼承

前言

在學(xué)習(xí) ES6 的 Class 知識(shí)之前我們需要先學(xué)習(xí) Object.defineProperty 方法题山,方法詳見(jiàn):本章 「案例」 defineProperty

class

介紹:js是一個(gè)腳本語(yǔ)言沒(méi)有像強(qiáng)語(yǔ)言一樣擁有類這樣一個(gè)概念,在ES6之前創(chuàng)建一個(gè)實(shí)例對(duì)象都使用的是構(gòu)造函數(shù)的方法故痊。ES6引入了class的概念顶瞳,通過(guò) class 關(guān)鍵字定義類,作為對(duì)象的模板。Class可以看作一個(gè)語(yǔ)法糖所以他的本質(zhì)就是一個(gè) function浊仆。class模板寫(xiě)法讓對(duì)象原型的寫(xiě)法更加清晰客峭、更像面向?qū)ο缶幊痰恼Z(yǔ)法。

基本語(yǔ)法

語(yǔ)法

  1. 通過(guò)class關(guān)鍵聲明的類可以認(rèn)為是構(gòu)造函數(shù)的另一種寫(xiě)法,同樣使用 new 關(guān)鍵字創(chuàng)建類實(shí)例對(duì)象
  2. 在前端開(kāi)發(fā)中我們約定類名首字母大寫(xiě)抡柿。類可以匿名也可具名
class App {
    // 這是一個(gè)具名類
}

let app = new App() // 創(chuàng)建 App 類的實(shí)例對(duì)象 

let Demo = class {
    // 這是一個(gè)匿名類
}

let demo = new Demo() // 創(chuàng)建 Demo 類的實(shí)例對(duì)象 
  1. 構(gòu)造函數(shù)的prototype屬性在class依然存在
class App {
           sayHello () {
               console.log('你好我是App')
           }

           sayGoodbye () {
               console.log('再見(jiàn)我是App')
           }
       }
 let app = new App()
 
 app.sayHello()   //   '你好我是App'
 app.sayGoodbye()   //  '再見(jiàn)我是App'    
 /*
 等價(jià)于
 class App () {}
 App.prototype = { 
           sayHello () {
               console.log('你好我是App')
           }

           sayGoodbye () {
               console.log('再見(jiàn)我是App')
           }
 }
*/

注意

  1. 我們打印上面的App類會(huì)發(fā)現(xiàn),類中的所有方法全部都存儲(chǔ)在類的prototype對(duì)象上面(即類的所有方法都是原型方法)
  2. class支持動(dòng)態(tài)屬性
let key = 'sayHello'
class App {
    [key]() {
               console.log('你好我是App')
    }
}
// App.prototype.sayHello()
// 函數(shù)也可以使用動(dòng)態(tài)函數(shù)名
function [key] () {
    
}
//等價(jià)于 function sayHello () { }
  1. 類內(nèi)部定義的屬性都是不可枚舉的
 class App {
           sayHello () {
               console.log('你好我是App')
           }

           sayGoodbye () {
               console.log('再見(jiàn)我是App')
           }
       }
     
for(key in App.prototype) { 
    // 這里不會(huì)被執(zhí)行
    console.log(key)
}

console.log(App.prototype)

constructor 方法

概念: constructor方法是類的構(gòu)造函數(shù),也是類的默認(rèn)方法舔琅。通過(guò)new關(guān)鍵字創(chuàng)建類的實(shí)例時(shí),會(huì)自動(dòng)調(diào)用 constructor 方法 面試題:new關(guān)鍵字到底做了什么

注意

  1. 一個(gè)類必須由constructor方法洲劣。如果創(chuàng)建class時(shí)沒(méi)有顯示定義constructor方法备蚓,class會(huì)默認(rèn)的隱式添加一個(gè)空的constructor方法
  2. constructor函數(shù)會(huì)隱式默認(rèn)的返回當(dāng)前實(shí)例對(duì)象(即this)。開(kāi)發(fā)人員可以顯示返回另一個(gè)對(duì)象這樣當(dāng)前class實(shí)例化后生成的就是 constructor函數(shù) 返回的新對(duì)象
class Demo {
            say() {
                console.log(123)
            }
        }


 class App {
           constructor() {
               return new Demo()
           }

           sayHello () {
               console.log('你好我是App', this)
           }

           sayGoodbye () {
               console.log('再見(jiàn)我是App')
           }
       }
     
 let app = new App()

console.log(app) // 這里的app 是 Demo 的實(shí)例對(duì)象
  1. class 只允許使用new關(guān)鍵字創(chuàng)建實(shí)例對(duì)象, 而不允許像構(gòu)造函數(shù)一樣直接調(diào)用囱稽。這一特性是他與構(gòu)造函數(shù)的主要區(qū)別
class App {
            sayHello() {
                console.log('你好我是App', this)
            }

            sayGoodbye() {
                console.log('再見(jiàn)我是App')
            }
        }

App() // Error  class不可在沒(méi)有new關(guān)鍵字情況下直接調(diào)用

實(shí)例屬性

概念:通過(guò)class塑造的實(shí)例對(duì)象自身的屬性(及this的屬性)

語(yǔ)法

  • 方法一: 在構(gòu)造函數(shù) constructor構(gòu)造函數(shù)中同this設(shè)置
 class App {
             constructor(name, age) {
                // 這里的this就是實(shí)例對(duì)象自身
                this.name = name
                this.age = age 
            }
}

let app = new App('小明', 12)
  • 方法二: 直接寫(xiě)在class中的屬性 屬性名 = 屬性值
class App {
     // 可以將所有的實(shí)例屬性寫(xiě)在class的頂部,可以直觀地看到當(dāng)前實(shí)例有哪些屬性
        a = 1
        b = function() {   }          
}
  • 方法三: 使用類的get/set創(chuàng)建實(shí)例屬性
    概念: 與ES5 一樣class可以在內(nèi)部使用get 和 set 關(guān)鍵字對(duì)某個(gè)屬性設(shè)置 get函數(shù)和set函數(shù),攔截該屬性的存取行為

語(yǔ)法: 下面實(shí)現(xiàn)了一個(gè)類似Vue數(shù)據(jù)發(fā)生改變對(duì)應(yīng)DOM更新的案例

class ObsVue {

            constructor(selecter, count) {
                this.html = document.getElementById(selecter)
                this._count = count
                this.inital()
                this.html.onclick = this.addCount.bind(this)
            }
            // 設(shè)置賦值攔截函數(shù) 當(dāng)給this.count賦值時(shí)該方法會(huì)被調(diào)用
            set count(value) {
                console.log('每次給this.count 賦值都會(huì)觸發(fā)set方法',value)
                this._count = value
                // 更新UI
                this.html.innerHTML = `你點(diǎn)擊了我${this.count}次`
            }
            // 設(shè)置取值攔截函數(shù) 當(dāng)獲取this.count時(shí)該方法會(huì)被調(diào)用
            get count() {
                // 每次獲取this.count屬性值 都會(huì)調(diào)用該函數(shù)
                // get 方法一定要有return值,他的返回值就是當(dāng)前屬性的值
                return this._count
            }

            inital() {
                this.html.innerHTML = `你點(diǎn)擊了我${this.count}次`
            }

            addCount() {
                console.log(this)
                this.count++
            }

        }



let obs = new ObsVue('app', 0)

obs.count = 17

靜態(tài)方法

概念:不會(huì)被實(shí)例對(duì)象所繼承的方法,只能通過(guò)class自身調(diào)用
語(yǔ)法:使用關(guān)鍵字static 聲明

class App {
       test () {
                console.log('原型方法')
       }

       static demo () {
                console.log('靜態(tài)方法')
       }

}

let app = new App()

console.log(app)

App.demo() // 只能通過(guò)類自身調(diào)用

注意

  1. 靜態(tài)方法內(nèi)部this指向構(gòu)造函數(shù)自身,不是類的實(shí)例
  2. 靜態(tài)可以被子類所繼承

靜態(tài)屬性

概念:不會(huì)被實(shí)例對(duì)象繼承的屬性就是靜態(tài)屬性,在class中只有靜態(tài)方法沒(méi)有靜態(tài)屬性郊尝。后來(lái)有一個(gè)提案提出使用static 關(guān)鍵字聲明靜態(tài)屬性
語(yǔ)法

 class App {
     static val = '靜態(tài)屬性'
}

console.log(App.val) // '靜態(tài)屬性'

私有屬性

概念: 在js中一直不存在真正的私有屬性。以往實(shí)現(xiàn)私有屬性的方法一共有以下幾種:

  • 方法一: 屬性名前加下劃線战惊,表示該屬性是一個(gè)私有屬性流昏,但是這種方法是不保險(xiǎn)的。即使加了下劃線該屬性在外部依然可以調(diào)用
class App {
     _val = '私有屬性'
}
  • 方法二: 使用模塊化吞获,因?yàn)槟K內(nèi)部的所有方法都是對(duì)外可見(jiàn)的况凉,將私有方法移出class模塊。
class App {
    name = '李雷'
 
    sayHello() {
        /* 調(diào)用私有方法 */
        bar.call(this)
    }
    
}
// 將私有方法移出
function bar() {
    console.log(this.name)
}
  • 方法三: Symbol
let a = Symbol('val')
class App {
    constructor () {
       this[a] = '私有屬性'
    }
}
  • 方法四: ES2020 中提案 用#開(kāi)頭聲明私有屬性
class App {
          // 私有屬性只能在constructor外部聲明
           #age = 14

           constructor() {
               this.name = '123'
               this.#age = 18
           }

           sayHello() {
               console.log(this.name, this.#age)
           }

}

let app = new App()

app.sayHello() // "123" 18

app.#age // Error 私有屬性不能再外部調(diào)用

類的繼承

概念: class 可以通過(guò) extend 關(guān)鍵字實(shí)現(xiàn)類的繼承
語(yǔ)法

 class Animal {
            constructor() {
                this.type = '動(dòng)物'
            }

            static show() {
                console.log('我是動(dòng)物的靜態(tài)方法')
            }

            static val = 10086

            sayHello() {
                console.log('hello')
            }
        }

class Cat extends Animal {

}

let cat = new Cat()

console.log(cat)

console.log(cat.type)

cat.sayHello()

Cat.show()

console.log(Cat.val) 

注意

使用了類的繼承的子類在其constructor函數(shù)中一定要調(diào)用一個(gè)super函數(shù),否則新建實(shí)例會(huì)報(bào)錯(cuò)各拷。

因?yàn)樵陬惖睦^承中子類的this對(duì)象必須調(diào)用父類constructor完成塑造刁绒,得到父類相同的屬性和方法,然后進(jìn)行加工返回子類的this,子類的this再加上子類自身的實(shí)例屬性方法烤黍。super其實(shí)就是父類的constructor方法知市。如果不在子類構(gòu)造函數(shù)內(nèi)部調(diào)用super,子類就沒(méi)有this對(duì)象速蕊。

注意如果子類沒(méi)有顯示聲明constructor函數(shù)嫂丙,ES6會(huì)自動(dòng)隱式創(chuàng)建constructor函數(shù)并在其內(nèi)部調(diào)用super方法。如果你的子類constructor中不需要設(shè)置實(shí)例屬性推薦隱式創(chuàng)建constructor函數(shù)

class Cat extends Animal {
    constructor() {
           super()    
     }
}

class Cat extends Animal {
   // 不顯示聲明 等價(jià)于上面的代碼,
   // 如果constructor中不需要做任何初始化操作 推薦不要顯示聲明constructor
}

super的屬性

概念: super就是父類構(gòu)造函數(shù),所以super與父類的構(gòu)造函數(shù)接收同樣參數(shù),在使用類的繼承時(shí)一定要記得給super傳遞參數(shù)
語(yǔ)法

class Animal {
            constructor(x,y) {
                this.x = x
                this.y = y
            }
        }
class Cat extends Animal {
            constructor(x,y,detail) {
                super(x,y)
                this.detail = detail
            }
        }

let cat = new Cat(1,2,'cat')

cat.x // 1
cat.y // 2
cat.detail // 'cat'

注意: 使用...語(yǔ)法可以簡(jiǎn)化 super 傳參問(wèn)題

class Animal {
            constructor(x,y) {
                this.x = x
                this.y = y
            }
        }
class Cat extends Animal {
            constructor(detail, ...props) {
                super(...props)
                this.detail = detail
            }
       }

let cat = new Cat('貓',1,3)
console.log(cat)
cat.detail // 貓
cat.x // 1
cat.y // 3

「拓展」 ES6其他API

Proxy

鏈接https://developer.mozilla.org/zh-cn/docs/web/javascript/reference/global_objects/proxy

Map

鏈接https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map

Set

鏈接https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Set

ArrayBuffer

鏈接https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer

合并空運(yùn)算符

概念: 判斷一個(gè)值是否為null,如果為null才返回后者
語(yǔ)法:使用??

let name = ""
let age = 0
let test = null

console.log(name || 'Max') // 'Max'
console.log(age || 18) // 18
console.log(test || 18) // 18

console.log(name ?? 'Max') // ""
console.log(age ?? 18) // 0
console.log(test ?? 18) // 18

可選的鏈接操作

概念: ES2020可以使用? 符號(hào)對(duì)一些可選屬性進(jìn)行判斷,若問(wèn)指定的可選屬性為空則返回undefined互例。
注意: ?符號(hào)只能用在鏈?zhǔn)秸{(diào)用中.不能以?結(jié)尾: data?.artist?.name? 錯(cuò)誤

let data = null
/*
// 模擬歌曲api返回的數(shù)據(jù)
    {
        id:10086
        artist: {
            name: '吳亦凡',
            id: 1000,
            alias: '十萬(wàn)伏特'
        }
    }
*/
// ES2020之前 異步數(shù)據(jù) 判斷其指定屬性是否存在
let artist = data && data.artist && data.artist.name
let alias = (data && data.artist && data.artist.alias) || ''
// ES2020
let artist = data?.artist?.name
let alias = data?.artist?.alias ?? ''

p.innerHTML = `${data.artist.name} (${data.artist.alias})`

動(dòng)態(tài)引入

概念: 如果您有一個(gè)寫(xiě)滿實(shí)用程序功能的文件奢入,而且其中某些功能可能很少使用,那么導(dǎo)入其所有依賴項(xiàng)可能只是浪費(fèi)資源媳叨。 現(xiàn)在腥光,我們可以使用async / await在需要時(shí)動(dòng)態(tài)導(dǎo)入依賴項(xiàng)。
語(yǔ)法: import('模塊路徑')

const doMath = async (num1, num2) => {
  if (num1 && num2) {
    const math = await import('./math.js');
    console.log(math.add(5, 10));
  };
};

doMath(4, 2); // 如果函數(shù)doMath 從來(lái)沒(méi)有被調(diào)用過(guò) './math.js'就永遠(yuǎn)不會(huì)被執(zhí)行
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末糊秆,一起剝皮案震驚了整個(gè)濱河市武福,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌痘番,老刑警劉巖捉片,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件平痰,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡伍纫,警方通過(guò)查閱死者的電腦和手機(jī)宗雇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)莹规,“玉大人赔蒲,你說(shuō)我怎么就攤上這事×际” “怎么了舞虱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)母市。 經(jīng)常有香客問(wèn)我矾兜,道長(zhǎng),這世上最難降的妖魔是什么患久? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任椅寺,我火速辦了婚禮,結(jié)果婚禮上墙杯,老公的妹妹穿的比我還像新娘配并。我一直安慰自己括荡,他們只是感情好高镐,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著畸冲,像睡著了一般嫉髓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邑闲,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天算行,我揣著相機(jī)與錄音,去河邊找鬼苫耸。 笑死州邢,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的褪子。 我是一名探鬼主播量淌,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼嫌褪!你這毒婦竟也來(lái)了呀枢?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤笼痛,失蹤者是張志新(化名)和其女友劉穎裙秋,沒(méi)想到半個(gè)月后琅拌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摘刑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年进宝,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浴鸿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片擎场。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡箭养,死狀恐怖财喳,靈堂內(nèi)的尸體忽然破棺而出吭露,到底是詐尸還是另有隱情玻孟,我是刑警寧澤夺姑,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布忍坷,位于F島的核電站蛹锰,受9級(jí)特大地震影響深胳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜铜犬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一舞终、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧癣猾,春花似錦敛劝、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至像捶,卻和暖如春上陕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拓春。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工释簿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人硼莽。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓庶溶,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親懂鸵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子偏螺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

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

  • 1. class類 1. 類的由來(lái): JavaScript 語(yǔ)言中,生成實(shí)例對(duì)象的傳統(tǒng)方法是通過(guò)構(gòu)造函數(shù)矾瑰。下面是一...
    最愛(ài)喝龍井閱讀 251評(píng)論 0 0
  • class Animal {//創(chuàng)建Animal類 constructor(species) { //cons...
    livcll學(xué)院閱讀 377評(píng)論 0 0
  • 前言 在之前我們學(xué)到的面對(duì)對(duì)象編程的思想中砖茸,我們?nèi)ソ鉀Q一個(gè)問(wèn)題去找對(duì)象,對(duì)象不存在我們便去創(chuàng)造對(duì)象殴穴; 那么我們之前...
    笑該動(dòng)人d閱讀 319評(píng)論 0 1
  • 簡(jiǎn)介 Class 可以通過(guò)extends關(guān)鍵字實(shí)現(xiàn)繼承凉夯,這比 ES5 的通過(guò)修改原型鏈實(shí)現(xiàn)繼承货葬,要清晰和方便很多。...
    codeSirCao閱讀 252評(píng)論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月劲够,有人笑有人哭震桶,有人歡樂(lè)有人憂愁,有人驚喜有人失落征绎,有的覺(jué)得收獲滿滿有...
    陌忘宇閱讀 8,531評(píng)論 28 53