什麼是行為委托?簡單來說就是一種設計模式,不同於傳統的構造函數的“類”式設計。 在這之前先說一下原型的基本知識。什麼是原型?簡單來說就是一個對象內部關聯另外一個對象,本質來說就是對象與對象之間的關聯;一個對象本身沒有屬性或者方法會到原型對象上查找。 這裡每個例子會通過構造函數,class和行為委托來 ...
什麼是行為委托?
簡單來說就是一種設計模式,不同於傳統的構造函數的“類”式設計。
在這之前先說一下原型的基本知識。
什麼是原型?簡單來說就是一個對象內部關聯另外一個對象,本質來說就是對象與對象之間的關聯;
一個對象本身沒有屬性或者方法會到原型對象上查找。
這裡每個例子會通過構造函數,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對象,如果兩個引用了一個兩個對象都不存在的屬性或者方法,那麼就會在原型鏈上形成無限迴圈。