【问题标题】:What are the advantages of having a separate init function on objects?对对象使用单独的 init 函数有什么好处?
【发布时间】:2014-10-17 03:05:26
【问题描述】:

我的意思是这样的代码:

 function MyObject(x, y, z) {
     this.init(x, y, z);
 }
MyObject.prototype = {
    constructor: MyObject,
    init: function(x, y, z) {
        // actually use x, y, z
    },
    other methods
};

为什么不直接不使用 init 方法并在构造函数中进行所有初始化?

【问题讨论】:

    标签: javascript


    【解决方案1】:

    没有。真的,没有。您的构造函数除了init 之外什么也不做。这或多或少是一种反模式。

    初始化对象的方法的优点是它可以被多次调用(在同一个对象上),用于对象池或仅用于重置它。然而,每个精心设计的 JS 对象都已经拥有该方法:它被称为.constructor()。它是构造函数,默认情况下可在其自己的原型上使用,并且通常在必要时显式放置(如您的示例中所做的那样)。

    这意味着拥有一个额外的init 方法相当无用,通常性能较差且更冗长。除非您使用这种冗长来强调(通过名称和声明风格)将其用作方法,并可能简化计划中的重构,以便实际的构造函数比init 方法(例如创建常量字段)。不过,我会避免过早地这样做,yagni。

    【讨论】:

    • init 可以被对象创建者覆盖并从constructor 调用,而无需处理super 实现(请参阅主干模型作为示例。)这个问题太有意见了——基于有效。
    • @Mathletics:不确定您所说的“对象创建者”是什么意思。但也可以只覆盖构造函数,即使某些继承框架认为使用init 方法更简单。
    • "对象创建者" == 作者;这就是为什么我尽量不要在累了的时候发帖:)
    • @Bergi:当父对象在闭包(私有变量)中保持状态时,重写构造函数失败。当你重写构造函数时为时已晚,你不再在父构造函数的范围内。
    • @slebetman:我不明白你所说的“你不再在父构造函数的范围内”是什么意思。您可以trivially call the super constructor 创建其私有状态变量。
    【解决方案2】:

    不幸的是,在 javascript 中,没有一种简洁的方法可以将参数向上传递到构造函数链,因为构造函数继承自对象,而不是其他构造函数。例如考虑以下内容:

    function Person (name) {
        this.name = name;
    }
    
    function Accountant () {}
    
    Accountant.prototype = new Person('');
    

    现在,如果您想创建一个 Accountant,则没有明确的方法可以为他命名:

    var x = new Accountant();
    

    当然,在这个简单的例子中,你可以简单地在创建他之后手动设置他的名字:

    x.name = 'Andy';
    

    但现实世界的代码可能并不总是那么容易解决。某些对象在闭包中保持状态,这意味着您无法将参数传递回父对象的构造函数,因为您在定义子对象的原型时已经创建了父对象。

    一种解决方法当然是根本不使用继承,而是使用装饰器函数,就像它们是构造函数一样:

    function new_person (name) {
        var self = {};
        self.name = name;
        return self;
    }
    
    function new_accountant (name) {
        var self = new_person(name);
        return self;
    }
    

    这种设计模式通常被称为寄生继承。请注意,在此设计模式中,我们不使用关键字 new

    如果您仍想使用正确的继承,另一种解决方法是让对象具有init 函数,任何想要继承它的构造函数都可以调用该函数:

    function Person (name) {
        this.init(name);
    }
    
    Person.prototype.init = function (name) {
        this.name = name;
    }
    
    function Accountant (name) {
        this.init(name);
    }
    
    Accountant.prototype = new Person('');
    

    当然还有其他更奇特的变通方法。这是 javascript,你只受到你的创造力的限制。但是对于原型继承,init 函数看起来是最简单的解决方法,需要最少的代码,而不需要额外的库或新版本的语言。

    【讨论】:

    • 你认为什么是“干净的方式”?顺便说一句,Accountant.prototype = new Person('')is not proper inheritance!
    猜你喜欢
    • 2016-05-07
    • 2012-10-09
    • 1970-01-01
    • 2011-06-19
    • 1970-01-01
    • 1970-01-01
    • 2013-04-28
    • 2012-11-30
    • 1970-01-01
    相关资源
    最近更新 更多