什麼是行為委託?
簡單來說就是一種設計模式,不同於傳統的建構函式的“類”式設計。
在這之前先說一下原型的基本知識。
什麼是原型?簡單來說就是一個物件內部關聯另外一個物件,本質來說就是物件與物件之間的關聯;
一個物件本身沒有屬性或者方法會到原型物件上查詢。
這裡每個例子會通過建構函式,class和行為委託來不同實現,不過不會評論class,是否使用class取決於你的觀點。
先看一個例子,建構函式寫法
function Foo(name) { this.name = name; } Foo.prototype.age = function() { console.log(this.name); }; function Fn(name) { Foo.call(this); this.name = name; } Fn.prototype = Object.create(Foo.prototype); Fn.prototype.constructor = Fn.prototype; Fn.prototype.set = function(value) { this.name = value; }; var a1 = new Fn(`zhangsan`); a1.age(); //zhangsan var a2 = new Fn(`lisi`); a2.set(`xiaowu`); a2.age(); //xiaowu
class寫法
class Foo { constructor(name) { this.name = name; } age() { console.log(this.name); } } class Fn extends Foo { constructor(name) { super(); this.name = name; } set(value) { this.name = value; } } var a1 = new Fn(`zhangsan`); a1.age(); //zhangsan var a2 = new Fn(`lisi`); a2.set(`xiaowu`); a2.age(); //xiaowu
行為委託寫法
var Foo = { const(name) { this.name = name; }, age() { console.log(this.name); } }; var Fn = Object.create(Foo); Fn.set = function (value) { this.name = value; }; var a1 = Object.create(Fn); a1.const(`zhangsan`); a1.age(); //zhangsan var a2 = Object.create(Fn); a2.set(`xiaowu`); a2.age(); //xiaowu
可以看到比起建構函式,行為委託是通過原型鏈來實現的,他值關心一件事情,物件指向的關係。
再來看一個複雜一些的例子,為dom新增樣式。
function Foo(value) { this.dom = value; } Foo.prototype.div = function () { var div = document.createElement(this.dom); this._dom = document.body.appendChild(div); return this._dom; }; Foo.prototype.get = function () { return this._dom; }; function Fn(text, cssText) { Foo.call(this, `div`); this.text = text; this.cssText = cssText; } Fn.prototype = Object.create(Foo.prototype); Fn.prototype.constructor = Fn.prototype; Fn.prototype.set = function () { this.div(); var div = this.get(); div.textContent = this.text; Object.keys(this.cssText).forEach((name) => { div.style.cssText += `${name}: ${this.cssText[name]}`; }); }; var a = new Fn(`hi`, {color: `red`, "font-size": `16px`}); a.set();
class寫法
class Foo { constructor(value) { this.dom = value; } div() { var div = document.createElement(this.dom); this._dom = document.body.appendChild(div); return this._dom; } get() { return this._dom; } } class Fn extends Foo { constructor(text, cssText) { super(`div`); this.text = text; this.cssText = cssText; } set() { super.div(); var div = super.get(); div.textContent = this.text; Object.keys(this.cssText).forEach((name) => { div.style.cssText += `${name}: ${this.cssText[name]}`; }); } } var a = new Fn(`hi`, { color: `red`, "font-size": `16px` }); a.set();
行為委託寫法
var Foo = { const(value) { this.dom = value; }, div() { var div = document.createElement(this.dom); this._dom = document.body.appendChild(div); return this._dom; }, get() { return this._dom; } }; var Fn = Object.create(Foo); Fn.constructor = function (text, cssText) { this.const.call(this, `div`); this.text = text; this.cssText = cssText; }; Fn.set = function () { this.div(); let div = this.get(); div.textContent = this.text; Object.keys(this.cssText).forEach((name) => { div.style.cssText += `${name}: ${this.cssText[name]}`; }); }; var a = Object.create(Fn); a.constructor(`hi`, { color: `red`, "font-size": `16px` }); a.set();
注意點:
1.在使用行為委託時要避免識別符號的重名,因為行為委託是基於原型鏈,不同於“類”的設計模式,可以建構函式與例項物件同時定義相同的名稱的識別符號。
2.兩個委託物件無法互相委託,假設一個a物件關聯b物件,然後b物件再關聯a物件,如果兩個引用了一個兩個物件都不存在的屬性或者方法,那麼就會在原型鏈上形成無限迴圈。