【问题标题】:JavaScript InheritanceJavaScript 继承
【发布时间】:2010-09-22 17:29:55
【问题描述】:

如果我有一个对象,我想从“超级对象”“继承”方法以确保一致性。它们将是混合变量。 修订

ParentObj = function()
{
    var self = this;
    this.interval = null
    this.name = "";
    this.timeout = 1000;

    this.stop = function()
    {
        clearInterval(self.interval);
    };

    this.start = function()
    {
        self.log("Starting up");
        setTimeout(function(){
            self.getData(true);
            self.interval = setInterval(function(){
                self.getData();
            }, self.timeout)
        }, 1000);
    };

    this.log = function(msg)
    {
        require("sys").log(self.name + ": " + msg);
    };

    this.getData = function(override)
    {
        if(override || self.interval)
        {
            /**
            * Allow
            */
            self.log(new Date());
        }
        else
        {
            self.log("Unable to override and no interval");
        }
    }
}

ChildObj = function()
{
    var self = this;
    this.name = "Child";
    this.timeout = 500;
    this.start();
    setTimeout(function(){
        self.stop();
    }, 2000);
}

ChildObj.prototype = new ParentObj();


var c = new ChildObj();

这似乎无法正常工作,特别是它没有看到self.interval 并且无法清除它。

我对其他 JavaScript 继承方法持开放态度,如果它们存在的话,但我真的需要开始将东西封装到父级中。有三四个相同的函数,但有时会更改,这意味着我必须运行十几个文件才能进行更改,而不是简单地更改父级。

通过一些建议,我试图更清楚地定义我要使用的功能类型。理想情况下,所有“孩子”都会有几个独特的设置(名称、间隔、配置设置)和 getData() 方法,而父母则负责管理启动、停止、日志记录和其他任何事情。

【问题讨论】:

    标签: javascript inheritance prototype


    【解决方案1】:
    • 通过将对象设为一次性函数的原型并使用“new”调用该函数来“克隆”对象。

    • 克隆父构造函数的原型,并将结果设置为子类的原型。

    ...

    /**
     * Extend a constructor with a subtype
     * @param {Function} superCtor      Constructor of supertype
     * @param {Function} subCtor        Constructor of subtype
     * @return {Function}               Constructor of subtype
     */
    var extend = (function(){
    
      return function (superCtor, subCtor) {
        var oldProto=subCtor.prototype;
        subCtor.prototype=clone(superCtor.prototype);
        return merge(subCtor.prototype, oldProto).constructor=subCtor; 
      }
    
      function Clone(){}
    
      /**
       * Clone an object
       * @param {Object}  obj     Object to clone
       * @return {Object}         Cloned object
       */
      function clone (obj) { Clone.prototype=obj; return new Clone() }
    
      /**
       * Merge two objects
       * @param {Object} dst      Destination object
       * @param {Object} src      Source object
       * @return {Object}         Destination object
       */
      function merge (dst, src) {
        for (var p in src) if (src.hasOwnProperty(p)) dst[p]=src[p];
        return dst;
      }
    
    }());
    

    【讨论】:

      【解决方案2】:

      使用这种继承方法,您只能在“上游”混合变量。您的子对象将能够看到其原型的公共属性,但原型不能看到其子对象的属性。它必须是独立的。

      (编辑:我刚刚注意到您也在使用“self”,而没有在 sobj 中声明它。)

      sobj = function()
      {
          var self = this;
          self.close = function()
          {
              clearInterval(self.interval);
          }
      
          self.interval = null;
      }
      cobj = function()
      {
          var self = this;
          self.interval = setInterval(function(){ /* Do something */}, 1000);
      }
      // set cobj.prototype - see explanation below
      

      关于如何正确设置原型(以及深入了解继承在 JS 中的工作原理),我建议您参阅 Douglas Crockford 的书JavaScript: The Good Parts

      他实际上已经在他的网站上发布了how to properly set the prototype。请务必使用 not touch Object.prototype 的版本,因为如果您更改它,许多脚本(对于初学者来说是 jQuery)会中断。

      【讨论】:

      • 不要在 super 上调用构造函数来获取对象实例作为 sub 的原型,这会产生令人讨厌的副作用并破坏事物。相反,“克隆”超级的原型并将其附加到子...查看我的答案。
      • 糟糕,复制和粘贴的速度有点太快了。 +1 指出我的错误,我会改正的。
      • 我可以使用其他继承方法吗?一个可能不进行上游合并的?
      • 您需要使用相当多的语法糖(否的答案就是一个很好的例子 - Crockford 在他的网站上也有一些模拟经典继承的方法)。但就“无糖”JavaScript 而言,没有。如果你说foo.x = 5 并且 x 没有明确定义为 foo 的成员,JavaScript 会查看foo.prototype 并继续搜索到Object.prototype。它看起来并不相反。因为 JavaScript 是鸭子类型的,所以扩展特定接口并不像 C++ 或 Java 这样的语言那么重要。
      【解决方案3】:

      首先,我认为var this.interval 不行。 var 关键字用于定义变量,但在您的情况下,您正在引用一个对象。

      其次,如果您想将“interval”声明为cobj 的方法,则必须将函数体包装在一个函数中。

      所以,这种方式对我有用:

      var sobj = function()
      {
          this.close = function()
          {
              clearInterval(this.interval);
          }
      }
       var cobj = function()
      {   
         this.initInterval = function(){ this.intervalid = setInterval(function(){ alert("test")}, 5000)};
         this.intervalid = null;
      }
      cobj.prototype = new sobj();
      
      var inst = new cobj();
      inst.initInterval();
      

      在我定义了构造函数之后,我创建了一个“cobj”对象的实际实例,然后调用“initInterval”来初始化“setInterval”。

      UPD:根据@MooGoo 的评论更新了代码。

      【讨论】:

      • 谁投了反对票,请发表评论 - 我真的很想知道我错在哪里。
      • -1 不是我的,但这是非常错误的。您不需要var self = this。在这种情况下,只做this.interval = 是一样的。此外,您正在为 interval 分配一个函数,而不是间隔 id。正确的代码是this.interval = setInterval(/*func*/, 1000);
      • @MooGoo,感谢您的评论,我不知何故没有意识到 OP 想要在构造函数中初始化间隔。更新了我的代码。
      • var self = 这是一个有用的语法糖,当您开始使用内部函数时会有所帮助。对于这个特定的示例,这不是必需的,但如果您返回并进行更改,这是一个有用的做法。你错的地方是需要一个围绕 setInterval 的包装器。只是没必要,实例化对象时会调用 setInterval。
      猜你喜欢
      • 2010-10-30
      • 2021-12-07
      • 2011-11-27
      • 2016-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-28
      相关资源
      最近更新 更多