更適用於JavaScript的設計模式:面向委托的設計,了解一下?(下)
阿新 • • 發佈:2019-01-16
對象 角度 實現 log 缺陷 面向 相對 rip light
先來看一下傳統的面向類式的寫法:
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 ? 請參考上一篇)
上面是傳統的,也是最為推崇的寄生組合式繼承模式,但是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的語法優勢在於沒有了prototype的混亂,很輕松地實現繼承,利用super方法輕松實現構造函數的復制,等同於傳統的call所實現的效果,extends實現委托機制,等同於Object.create所實現的效果。
但是缺陷在於加深了人們對於類以及繼承的誤解。
我們再來看利用委托的設計模式:
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的出現,也沒有new構造函數調用,完全依靠委托的機制,完全是對象之間的聯系。這種設計模式要求我們不再利用多態去重寫原有的函數或屬性,而是用不同的函數名或屬性名消除這種歧義。
可能存在的缺陷是之前的new構造函數被分成了兩段代碼。
var bar = Object.create(Bar); bar.inits(‘bar‘, 14);
但是有一個好處在於我們可以關註點分離,使得創建和初始化分離。
以上三種是目前主流的實現仿類以及繼承的範式,第二種目前相對較為流行,第三種更生僻一些,但是卻最符合JavaScript的設計思想,沒有類的概念,沒有構造函數,只有對象與對象的聯系,行為委托。並不強求一定要用哪一種,還是看個人喜好吧,因為很難講三者的優勝好壞。
end
更適用於JavaScript的設計模式:面向委托的設計,了解一下?(下)