【问题标题】:Can I "extend" a closure-defined "class" in Javascript?我可以在 Javascript 中“扩展”闭包定义的“类”吗?
【发布时间】:2011-04-03 10:26:51
【问题描述】:

我有一个这样定义的 Javascript“类”:

var Welcomer = function(name) {
  var pName = name;
  var pMessage = function() {
    return "Hi, " + pName + "!";
  };

  return {
    sayHi: function() {
      alert(pMessage());
    }
  };
};

new Welcomer('Sue').sayHi();

有没有办法“子类化”Welcomer,使我可以重新定义公共方法并访问私有方法和变量?以下将允许我访问公共方法,但不能访问私有方法:

var UnhappyWelcomer = function(name) {
  var pSadMessage = function() {
    // won't work, b/c I don't have access to pMessage
    return pMessage() + " Miserable day, innit?";
  };

  return {
    sayHi: function() {
      alert(pSadMessage());
    }
  };
};
UnhappyWelcomer.prototype = Welcomer(); // failed attempt at inheritance

new UnhappyWelcomer().sayHi();

【问题讨论】:

  • 您可能需要阅读this article
  • 为那篇文章添加书签。谢谢

标签: javascript inheritance closures scoping


【解决方案1】:

您的问题的简单答案是

你不能做任何事情来访问那些var定义的东西,除非你的函数在同一个范围内,或者你以某种方式“公开”信息(通过返回它,或者将它设置在this )。

但是,如果您有权编辑原始函数,则可以重写内容,使这些函数可以“传递”到扩展函数中,从而改变对象的“受保护”范围。下面的代码应该可以很好地理解我的提议。

var Welcomer = function(name) {
  var _protected = {
    name: name,
    message: function() {
      return "Hi, " + _protected.name + "!";
    }
  };

  return {
    extendWith: function(extender) {
      extender.call(this, _protected);
      return this;
    },
    sayHi: function() {
      alert(_protected.message());
    }
  };
};

var UnhappyWelcomer = function(name) {
  var self = Welcomer(name).extendWith(function(_protected) {
    _protected.sadMessage = function() {
       return _protected.message() + " Miserable day, innit?";
    };
    // extending the public while still having scope to _protected...
    this.sayHi = function() {
      alert(_protected.sadMessage());
    };
  });
  return self;
};

UnhappyWelcomer('bob').sayHi();

【讨论】:

  • 我当然确实可以访问原始功能,所以我很想以这样一种方式编写它,以使事物“受保护”而不是“私有”。你能举个例子吗?
【解决方案2】:

“类”模式不是“类”模式,它被称为Module Pattern。它返回一个与创建它的函数没有联系的对象,除了它的私有变量的可用性。返回的对象不是创建它的函数的实例。

当您调用“new Class()”时,它确实会创建该函数的一个实例,但它也会返回另一个对象。任何进一步的操作实际上是在返回的对象上而不是实例上。

为了使用继承,你确实需要正确使用原型继承,我建议你阅读:

进一步阅读:

很抱歉给您留下阅读材料,但在我看来,您正在探索各种可能性。这些文章将对此事有更深入的了解。

一旦您对此事有更多了解,您很可能会完全忽略私有成员并使用 _ 前缀,并像其他所有人一样将其设为公共成员;)这更容易,而且私有成员无论如何都是毫无意义的。

【讨论】:

    【解决方案3】:

    如果你真的需要继承,有一些库可以提供极大的帮助。一个选项是trait.js,它实际上可能在某个时候成为 javascript 的标准部分。如果这不能让你浮出水面,像 jQuery 和原型这样的库有继承帮助器。

    如果您想采用最小/从头开始的方法,我强烈建议您对所有事情都使用原型模型。与示例中的模式相比,您将看到性能大幅提升。

    为了更直接地解决您的问题,不。如果您设计“类”以便不依赖私有函数,您将拥有更轻松的时间。

    【讨论】:

    • 我试过return jQuery.extend({}, Welcomer(), { sayHi: function() { alert(pSadMessage()); });,但extend 显然只复制对象字面量(公共方法)中定义的元素,而不是闭包范围。
    • 是的,您使用构造函数中定义的私有变量/函数设计“类”的方式,它们只是不可见,这就是为什么我肯定会转向更标准的原型基于结构
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-10
    • 2016-02-05
    • 2010-10-21
    • 2015-06-27
    • 1970-01-01
    相关资源
    最近更新 更多