【问题标题】:Javascript apply — Inheriting classesJavascript 应用——继承类
【发布时间】:2011-08-18 16:19:23
【问题描述】:

以下代码改编自this answer

    function MessageClass() {
        var self = this;
        this.clickHander = function(e) { self.someoneClickedMe = true; };

        var _private = 0;
        this.getPrivate = function() { return _private; };
        this.setPrivate = function(val) { _private = val; };
    }

    ErrorMessageClass.prototype = new MessageClass();
    function ErrorMessageClass() {
        MessageClass.apply(this, arguments);
    }

    var errorA = new ErrorMessageClass();
    var errorB = new ErrorMessageClass();
    errorA.setPrivate('A');
    errorB.setPrivate('B');
    console.log(errorA.getPrivate()); 
    console.log(errorB.getPrivate());

原来的帖子没有MessageClass.apply(this, arguments);,因为它的目的是展示继承在 Javascript 中是如何出错的。

我的问题是:ErrorMessageClass.prototype = new MessageClass();之前 ErrorMessageClass 构造函数甚至被宣布为不好的做法?我的理解是,像这样调用未声明的标识符会导致发生静默声明,结果被放置在全局窗口对象上,我理解这是不好的。

是这种形式吗:

    function ErrorMessageClass() {
        MessageClass.apply(this, arguments);
    }
    ErrorMessageClass.prototype = new MessageClass();

被认为是更好的做法? This link 显示了上面最初编写的代码,这就是我什至尝试它的原因。这位博主是否知道一些我不知道的事情(很可能)?

编辑

下面的答案中有很多很棒的信息,但我确实想强调this link,它确实完美地解释了事情

【问题讨论】:

    标签: javascript


    【解决方案1】:

    通常,为了避免这种混淆,您只需在后面附加原型,但正如 Adam Rackis 指出的那样,函数声明会像 var 语句一样被提升。

    但是,您不应将基础对象实例化为原型。如果您的基础对象接受参数,您应该使用什么?使用空的“代理”构造函数

    // Used to setup inheritance
    function surrogate () {};
    
    
    function MessageClass() {
        var self = this;
        this.clickHander = function(e) { self.someoneClickedMe = true; };
    
        var _private = 0;
        this.getPrivate = function() { return _private; };
        this.setPrivate = function(val) { _private = val; };
    }
    
    // The key steps to creating clean inheritance
    surrogate.prototype = MessageClass;
    // Sets up inheritance without instantiating a base class object
    ErrorMessageClass.prototype = new surrogate();
    // Fix the constructor property
    ErrorMessageClass.prototype.constructor = ErrorMessageClass
    
    function ErrorMessageClass() {
        MessageClass.apply(this, arguments);
    }
    

    还有很多要说的。 http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

    【讨论】:

    • +1 绝对不要构造和初始化一个真实的对象以用作原型。请参阅this question 了解背景信息以及在方法中包装“代理”、提供单独的初始化程序等的一些示例。
    • 我基本同意,但您认真考虑在可用的情况下使用Object.create(),在不可用的情况下使用emulating it。并不是说它改变了什么,仿真基本上使用与您的代码相同的方法。
    • 那我为什么要使用它呢?因为 Douglas Crockford 说 new 运算符很危险?
    【解决方案2】:

    它之所以有效,是因为函数声明首先被评估。如果您尝试将这些类移动到对象字面量“命名空间”下,第一个版本将会失败。

    我个人觉得第二种方法更容易阅读——另外,不要忘记将子类的prototype.constructor 属性设置回自身。就个人而言,我在 Function 原型上使用了一个 inherits() 方法,它基本上包含了您在此处使用的代码类型。

    【讨论】:

    • “函数声明首先被评估”是什么意思?您是说函数 ErrorMessageClass() ... 将在 ErrorMessageClass.Prototype = ... 之前进行评估,即使它被声明为第二个?我认为解释型语言无法做到这一点
    • 这可能会有所帮助 - stackoverflow.com/questions/3887408/…
    • @Adam:是的。 JavaScript 充满了惊喜!如果您不想要“函数提升”,您可以将函数编写为 FunctionExpression 而不是神奇的 FunctionDeclaration 语句:var ErrorMessageClass= function() { ... };
    • 那个链接很好地解释了事情。谢谢。
    猜你喜欢
    • 2011-11-27
    • 1970-01-01
    • 2011-12-20
    • 2015-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    相关资源
    最近更新 更多