一吠架、簡(jiǎn)介
JavaScript 語(yǔ)言中锋喜,生成實(shí)例對(duì)象的傳統(tǒng)方法是通過(guò)構(gòu)造函數(shù)凡涩。下面是一個(gè)例子棒搜。
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.showName = function(){
return this.name;
}
var p1 = new Person('jack', 24);
console.log(p1.showName()); // jack
ES6 提供了更接近傳統(tǒng)語(yǔ)言的寫(xiě)法,引入了 Class(類)這個(gè)概念活箕,作為對(duì)象的模板力麸。通過(guò) class
關(guān)鍵字,可以定義類育韩。
基本上克蚂,ES6 的 class
可以看作只是一個(gè)語(yǔ)法糖,它的絕大部分功能筋讨,ES5 都可以做到埃叭,新的 class
寫(xiě)法只是讓對(duì)象原型的寫(xiě)法更加清晰、更像面向?qū)ο缶幊痰恼Z(yǔ)法而已悉罕。上面的代碼用 ES6 的 class
改寫(xiě)赤屋,就是下面這樣误墓。
//定義類
class Person{
constructor(name, age) {
this.name = name;
this.age = age;
}
showName() {
return this.name;
}
}
上面代碼定義了一個(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è) showName
方法。注意妨蛹,定義“類”的方法的時(shí)候屏富,前面不需要加上 function
這個(gè)關(guān)鍵字,直接把函數(shù)定義放進(jìn)去了就可以了蛙卤。另外狠半,方法之間不需要逗號(hào)分隔,加了會(huì)報(bào)錯(cuò)颤难。
ES6 的類神年,完全可以看作構(gòu)造函數(shù)的另一種寫(xiě)法。
class Person{
}
typeof Person // "function"
Person === Person.prototype.constructor // true
上面代碼表明行嗤,類的數(shù)據(jù)類型就是函數(shù)已日,類本身就指向構(gòu)造函數(shù)。
使用的時(shí)候栅屏,也是直接對(duì)類使用 new
命令飘千,跟構(gòu)造函數(shù)的用法完全一致。
二栈雳、嚴(yán)格模式
嚴(yán)格模式
類和模塊的內(nèi)部护奈,默認(rèn)就是嚴(yán)格模式,所以不需要使用use strict指定運(yùn)行模式甫恩。只要你的代碼寫(xiě)在類或模塊之中逆济,就只有嚴(yán)格模式可用。
考慮到未來(lái)所有的代碼磺箕,其實(shí)都是運(yùn)行在模塊之中奖慌,所以 ES6 實(shí)際上把整個(gè)語(yǔ)言升級(jí)到了嚴(yán)格模式。
三松靡、constructor 方法
constructor
方法是類的默認(rèn)方法简僧,通過(guò) new
命令生成對(duì)象實(shí)例時(shí),自動(dòng)調(diào)用該方法雕欺。一個(gè)類必須有constructor
方法岛马,如果沒(méi)有顯式定義棉姐,一個(gè)空的 constructor
方法會(huì)被默認(rèn)添加。
class Person {
}
// 等同于
class Person {
constructor() {}
}
四啦逆、Class 的繼承
Class 可以通過(guò) extends
關(guān)鍵字實(shí)現(xiàn)繼承伞矩,這比 ES5 的通過(guò)修改原型鏈實(shí)現(xiàn)繼承,要清晰和方便很多夏志。
class Person {
}
class Man extends Person {
}
上面代碼定義了一個(gè) Man
類乃坤,該類通過(guò) extends
關(guān)鍵字,繼承了 Person
類的所有屬性和方法沟蔑。但是由于沒(méi)有部署任何代碼湿诊,所以這兩個(gè)類完全一樣,等于復(fù)制了一個(gè) Person
類瘦材。下面厅须,我們?cè)?Man
內(nèi)部加上代碼。
class Man extends Person {
constructor(name, age, job) {
super(name, age); // 調(diào)用父類的constructor(name, age)
this.job = job;
}
showJob() {
return 'My name is ' + super.showName() + ',I am a ' + this.job; // 調(diào)用父類的 sayName()
}
}
var person1 = new Man('jack',26,'FED');
console.log(person1.sayJob()) // "My name is jack,I am a FED"
上面代碼中食棕,constructor
方法和 showJob
方法之中朗和,都出現(xiàn)了super關(guān)鍵字,它在這里表示父類的構(gòu)造函數(shù)簿晓,用來(lái)新建父類的 this
對(duì)象例隆。
子類必須在 constructor
方法中調(diào)用 super
方法,否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò)抢蚀。這是因?yàn)樽宇悰](méi)有自己的 this
對(duì)象镀层,而是繼承父類的 this
對(duì)象,然后對(duì)其進(jìn)行加工皿曲。如果不調(diào)用 super
方法唱逢,子類就得不到 this
對(duì)象。
class Person {
}
class Man extends Person {
constructor() {
}
}
var man = new Man(); // ReferenceError
上面代碼中屋休,Man
繼承了父類 Person
坞古,但是它的構(gòu)造函數(shù)沒(méi)有調(diào)用 super
方法,導(dǎo)致新建實(shí)例時(shí)報(bào)錯(cuò)劫樟。
ES5 的繼承痪枫,實(shí)質(zhì)是先創(chuàng)造子類的實(shí)例對(duì)象 this
,然后再將父類的方法添加到 this
上面(Parent.apply(this)
)叠艳。ES6 的繼承機(jī)制完全不同奶陈,實(shí)質(zhì)是先創(chuàng)造父類的實(shí)例對(duì)象this(所以必須先調(diào)用super
方法),然后再用子類的構(gòu)造函數(shù)修改 this
附较。
如果子類沒(méi)有定義 constructor
方法吃粒,這個(gè)方法會(huì)被默認(rèn)添加,代碼如下拒课。也就是說(shuō)徐勃,不管有沒(méi)有顯式定義事示,任何一個(gè)子類都有 constructor
方法。
class Man extends Person {
}
// 等同于
class Man extends Person {
constructor(...args) {
super(...args);
}
}
另一個(gè)需要注意的地方是僻肖,在子類的構(gòu)造函數(shù)中肖爵,只有調(diào)用 super
之后,才可以使用this關(guān)鍵字臀脏,否則會(huì)報(bào)錯(cuò)遏匆。這是因?yàn)樽宇悓?shí)例的構(gòu)建,是基于對(duì)父類實(shí)例加工谁榜,只有 super
方法才能返回父類實(shí)例。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
class Man extends Person {
constructor(name, age, job) {
this.job = job; // ReferenceError
super(name, age);
this.job = job; // 正確
}
}
上面代碼中凡纳,子類的 constructor
方法沒(méi)有調(diào)用 super
之前窃植,就使用 this
關(guān)鍵字,結(jié)果報(bào)錯(cuò)荐糜,而放在
super
方法之后就是正確的巷怜。
下面是生成子類實(shí)例的代碼。
let man = new Man('jack', 26, 'FED');
man instanceof Man // true
man instanceof Person // true
上面代碼中暴氏,實(shí)例對(duì)象 man
同時(shí)是 Man
和 Person
兩個(gè)類的實(shí)例延塑,這與 ES5 的行為完全一致。
最后答渔,父類的靜態(tài)方法关带,也會(huì)被子類繼承。
class A {
static hello() {
console.log('hello world');
}
}
class B extends A {
}
B.hello() // hello world
上面代碼中沼撕,hello()是A類的靜態(tài)方法宋雏,B繼承A,也繼承了A的靜態(tài)方法务豺。
五磨总、super關(guān)鍵字
super
這個(gè)關(guān)鍵字,既可以當(dāng)作函數(shù)使用笼沥,也可以當(dāng)作對(duì)象使用蚪燕。在這兩種情況下,它的用法完全不同奔浅。
第一種情況馆纳,super
作為函數(shù)調(diào)用時(shí),代表父類的構(gòu)造函數(shù)汹桦。ES6 要求厕诡,子類的構(gòu)造函數(shù)必須執(zhí)行一次super
函數(shù)。
class A {}
class B extends A {
constructor() {
super();
}
}
上面代碼中营勤,子類B的構(gòu)造函數(shù)之中的super()灵嫌,代表調(diào)用父類的構(gòu)造函數(shù)壹罚。這是必須的,否則 JavaScript 引擎會(huì)報(bào)錯(cuò)寿羞。
(略)