更适用于JavaScript的设计模式:面向委托的设计,了解一下?(下)

先来看一下传统的面向类式的写法:

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

原文地址:https://www.cnblogs.com/yanchenyu/p/10275601.html