为什么“代理”继承停止使用闭包?

时间:2012-12-30 18:26:23

标签: javascript node.js inheritance module closures

对于那些不熟悉的人,代理继承如下所示:

var Surrogate = function () {}

var extend = function (Base, Sub) {
  Surrogate.prototype = Base.prototype;
  Sub.prototype = new Surrogate();
  Sub.prototype.constructor = Sub;
}

var Animal = function (name) {
  this.name = name;
};

Animal.prototype.speak = function () {
  return this.getSound() + ' ' + this.name;
};

Animal.prototype.getSound = function () {
  // Abstract
};

var Cat = function (name) {
  Animal.call(this, name);
};

extend(Animal, Cat);

Cat.prototype.getSound = function () {
  return 'Meow';
};

var kitty = new Cat('Maru');
console.log(kitty.speak()); // Logs "Meow Maru"
console.log(kitty instanceof Animal); // Logs true
console.log(kitty instanceof Cat); // Logs true
console.log(kitty.constructor == Cat); // Logs true

基本上要创建一个继承自Animal的构造函数,我们创建另一个构造函数(在本例中为Cat),使用适当的{Animal构造函数调用this构造函数{1}},然后使用extend函数将Cat的原型设置为Animal的“实例”,而不使用name属性。考虑使用extend(Animal, Cat)Cat.prototype = new Animal()相同,但Cat.prototype.name未定义。

上述情况完美无缺,我稍后会对此提出质疑。

我希望将其提升到一个新级别,并将Surrogate隐藏在闭包中,因此我将Surrogateextend的声明更改为如下所示:

var extend = (function () {
  var Surrogate = function () {};
  return function (Base, Sub) {
    Surrogate.prototype = Base.prototype;
    Sub.prototype = new Surrogate();
    Sub.prototype.constructor = Sub;
  };
});

现在,当我运行脚本时,它在第一个日志语句中失败:

TypeError: Object [object Object] has no method 'speak'

但是,使用以下内容创建另一个文件extend.js

var Surrogate = function () {};

module.exports = function (Base, Sub) {
  Surrogate.prototype = Base.prototype;
  Sub.prototype = new Surrogate();
  Sub.prototype.constructor = Sub;
}

将主脚本中extend的声明更改为var extend = require('./extend');有效,Surrogate按预期隐藏。

对于主要问题:据我所知,节点和其他CommonJS系统只是将模块封装在一个闭包函数中,就像我最初尝试的那样。为什么模块版本可行,但我的带闭包的版本没有?

对于上面提到的附带问题:我对Sub.prototype.constructor = Sub感到惊讶。我认为它应该是Sub.prototype.constructor = Base,但这导致最后一个日志记录语句记录false。我想我已经为自己回答了这个问题,但我认为constructor是构造对象的属性,而不是原型。是相反吗?

更新

我刚刚使用名为extend的模块对AMD进行了尝试,其定义如下:

define(function () {
  var Surrogate = function () {};

  return function (Base, Sub) {
    Surrogate.prototype = Base.prototype;
    Sub.prototype = new Surrogate();
    Sub.prototype.constructor = Sub;
  };
});

它完美无缺。我觉得我在这里忽略了一些非常简单的东西...为什么这在模块系统中工作得很好而在普通闭包中却没有?我已经测试了node.js,Chrome和Firefox中的所有版本(普通版,闭包版和模块版)。

1 个答案:

答案 0 :(得分:1)

var extend = (function () {
  var Surrogate = function () {};
  return function (Base, Sub) {
    Surrogate.prototype = Base.prototype;
    Sub.prototype = new Surrogate();
    Sub.prototype.constructor = Sub;
  };
});

应该是

var extend = (function () {
  var Surrogate = function () {};
  return function (Base, Sub) {
    Surrogate.prototype = Base.prototype;
    Sub.prototype = new Surrogate();
    Sub.prototype.constructor = Sub;
  };
})();

(我只是附加了()来执行该功能。)

或者如果你想防止Surrogate可能被破坏的可能性(某些人可能会破坏它的构造函数 - 让它做一些事情):

var extend = function (Base, Sub) {
    var Surrogate = function () {};
    Surrogate.prototype = Base.prototype;
    Sub.prototype = new Surrogate();
    Sub.prototype.constructor = Sub;
};