前言
雖然 ES 6 里引入了「類」這個(gè)概念,但是實(shí)際上 ES 6 的類只是 ES 5 的語(yǔ)法糖,本質(zhì)上還是一個(gè)「構(gòu)造函數(shù)」。本片筆記主要回顧 ES 5 通過(guò)構(gòu)造函數(shù)創(chuàng)建對(duì)象的一般方法,以及 ES 5 中類的繼承的一般方法;然后再介紹 ES 6 的寫法。
ES 5 中通過(guò)構(gòu)造函數(shù)創(chuàng)建對(duì)象和實(shí)現(xiàn)類繼承的一般方法
此部分涉及的內(nèi)容基本出自《JavaScript 高級(jí)程序設(shè)計(jì)(第 3 版)》第六章:「面向?qū)ο蟮某绦蛟O(shè)計(jì)」,里面介紹了不少種創(chuàng)建對(duì)象的方法和實(shí)現(xiàn)繼承的方法,這里我只從這些方法里各挑出一種最為廣泛使用的方法。首先是書上所謂的「組合使用構(gòu)造函數(shù)模式和原型模式」的創(chuàng)建對(duì)象的方法:
function Person(name, age, job) {
this.name = name
this.age = age
this.job = job
this.friends = [ 'Shelby', 'Court' ]
}
Person.prototype = {
constructor: Person,
sayName: function() {
alert(this.name)
}
}
Person.doSomething = function() {
// do something
}
Person.aProperty = 'a property'
上面就是一個(gè)「類」:每個(gè)實(shí)例都擁有的各自不同的屬性放到構(gòu)造函數(shù)內(nèi)部,通過(guò) this 來(lái)初始化;所有實(shí)例都共享的方法放到構(gòu)造函數(shù)的 prototype 上;同時(shí)這個(gè)類本身還有一些只是自己所有的屬性或方法,別的面向?qū)ο笳Z(yǔ)言里稱之為靜態(tài)屬性(方法),這些靜態(tài)屬性直接掛到構(gòu)造函數(shù)本身上。通過(guò) new 操作符執(zhí)行這個(gè)函數(shù)就可以得到對(duì)應(yīng)的實(shí)例對(duì)象,所有的對(duì)象都有著自己的 name、age、job、friends 屬性,同時(shí)共享原型對(duì)象上的 sayName 方法。上面就是 ES 5 里一個(gè)類的基本創(chuàng)建方法,當(dāng)然如果要做的更好一點(diǎn)的話可以把 constructor 單獨(dú)用 Object.defineProperty 來(lái)寫,因?yàn)榘凑丈厦娴膶懛ㄋ?enumerable 的屬性將會(huì)是 true,而實(shí)際上是 false 的。
再來(lái)看看類的繼承,書上所謂「寄生組合式繼承」,其原理就是在子類的中調(diào)用父類,但是把 this 的值綁定成子類,然后在維護(hù)好原型鏈,將 Object.create(prototype) 賦值給子類的 prototype 同時(shí)將 prototype 的 constructor 屬性指向子類本身:
function Teacher(name, age, subject) {
Person.call(this, name, age, 'teacher')
this.subject = subject
}
Teacher.prototype = Object.create(
Person.prototype,
{
constructor: {
value: Teacher,
writable: true,
configurable: true,
enumerable: false
},
teach: function() {
// teach something
}
}
)
上面的代碼就完成了 Teacher 類對(duì) Person 的繼承。
ES 6 中對(duì)應(yīng)的寫法
class Person {
constructor(name, age, job) {
this.name = name
this.age = age
this.job = job
this.friends = [ 'Shelby', 'Court' ]
}
sayName() {
alert(this.name)
}
static soSomething() {
// do something
}
}
Person.aProperty = 'a property'
上面就是 ES 6 中類的寫法,看起來(lái)簡(jiǎn)潔很多了。但是好像對(duì)于靜態(tài)屬性,ES 6 目前還沒(méi)支持到這一步,所以也還是只能單獨(dú)寫。然后看下繼承:
class Teacher extends Person {
constructor(name, age, subject) {
super(name, age, 'teacher ')
this.subject = subject
}
teach() {
// teach something
}
}
需要注意的是,當(dāng)子類想在 constructor 里引用 this 必須提前調(diào)用父類的構(gòu)造函數(shù) super() ,不然會(huì)報(bào)錯(cuò),這是因?yàn)?「ES 6 的繼承機(jī)制與上面 ES 5 的機(jī)制不同,ES 6 的機(jī)制是先由父類創(chuàng)建 this 值,然后再由子類的 contructor 去修改這個(gè)值」,這是我在 ES 6 相關(guān)的書上看到的,具體怎么個(gè)做法,暫時(shí)不得而知,不知道 Babel 會(huì)不會(huì)是按照 ES 6 的機(jī)制做的 transform。以上只是 class 的最基本的用法,剩下的一些特性下次詳細(xì)介紹。