行為委託

boses發表於2018-09-02

什麼是行為委託?
簡單來說就是一種設計模式,不同於傳統的建構函式的“類”式設計。

在這之前先說一下原型的基本知識。
什麼是原型?簡單來說就是一個物件內部關聯另外一個物件,本質來說就是物件與物件之間的關聯;
一個物件本身沒有屬性或者方法會到原型物件上查詢。

這裡每個例子會通過建構函式,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物件,如果兩個引用了一個兩個物件都不存在的屬性或者方法,那麼就會在原型鏈上形成無限迴圈。

 

相關文章