先來看一下傳統(tǒng)的面向類式的寫法:
function Foo(name) { this.name = name; } Foo.prototype.sayName = function() { console.log('name: ' + this.name) } function Bar(name, age) { Foo.call(this, name); this.age = age; } Bar.prototype = Object.create(Foo.prototype); Bar.prototype.sayAge = function() { console.log('age: ' + this.age) } var bar1 = new Bar('bar1', 13); bar1.sayName(); bar1.sayAge();
這里的Object.create也可以替換成Object.setPrototypeOf,但是我們這里并不care它的constructor指向是否正確,所以從可讀性的角度我們用Object.create。(why ? 請參考上一篇)
上面是傳統(tǒng)的,也是最為推崇的寄生組合式繼承模式,但是es6誕生以后,這種寫法就不再流行了,更多的是利用class的語法糖,我們來看代碼:
class Foo { constructor(name) { this.name = name; } sayName() { console.log('name: ' + this.name); } } class Bar extends Foo { constructor(name, age) { super(name); this.age = age; } sayAge() { console.log('age: ' + this.age); } } var bar3 = new Bar('bar3', 15); bar3.sayName(); bar3.sayAge();
class的語法優(yōu)勢在于沒有了prototype的混亂,很輕松地實現(xiàn)繼承,利用super方法輕松實現(xiàn)構(gòu)造函數(shù)的復(fù)制,等同于傳統(tǒng)的call所實現(xiàn)的效果,extends實現(xiàn)委托機制,等同于Object.create所實現(xiàn)的效果。
但是缺陷在于加深了人們對于類以及繼承的誤解。
我們再來看利用委托的設(shè)計模式:
Foo = { init(name) { this.name = name }, sayName() { console.log('name: ' + this.name); } } Bar = Object.create(Foo); Bar.inits = function(name, age) { Foo.init.call(this, name); this.age = age; } Bar.sayAge = function() { console.log('age: ' + this.age); } var bar = Object.create(Bar); bar.inits('bar', 14); bar.sayName(); bar.sayAge();
同樣,這里沒有prototype的出現(xiàn),也沒有new構(gòu)造函數(shù)調(diào)用,完全依靠委托的機制,完全是對象之間的聯(lián)系。這種設(shè)計模式要求我們不再利用多態(tài)去重寫原有的函數(shù)或?qū)傩?,而是用不同的函?shù)名或?qū)傩悦@種歧義。
可能存在的缺陷是之前的new構(gòu)造函數(shù)被分成了兩段代碼。
var bar = Object.create(Bar); bar.inits('bar', 14);
但是有一個好處在于我們可以關(guān)注點分離,使得創(chuàng)建和初始化分離。
以上三種是目前主流的實現(xiàn)仿類以及繼承的范式,第二種目前相對較為流行,第三種更生僻一些,但是卻最符合JavaScript的設(shè)計思想,沒有類的概念,沒有構(gòu)造函數(shù),只有對象與對象的聯(lián)系,行為委托。并不強求一定要用哪一種,還是看個人喜好吧,因為很難講三者的優(yōu)勝好壞。
以上就是今天分享的內(nèi)容了,感興趣的同學(xué)可以留言一起討論哈!
文字免費,但碼字不易,記得點贊!
感興趣可關(guān)注一波,謝謝!
浙公網(wǎng)安備 33010602011771號