简体   繁体   English

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

[英]Why does “surrogate” inheritance stop working with closures?

For those not familiar, surrogate inheritance looks like the following: 对于不熟悉的人,代理继承如下所示:

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

Basically to create a constructor function which inherits from Animal , we create another constructor function (in this case, Cat ), call the Animal constructor function with the proper value for this , and then use the extend function to set the Cat 's prototype to be an "instance" of Animal without a name property. 基本上以创建从继承一个构造函数Animal ,我们创建另一个构造函数(在这种情况下, Cat ),调用Animal与适当的值构造函数this ,然后使用extend函数来设置Cat的原型是不带name属性的Animal的“实例”。 Think of using extend(Animal, Cat) being the same as Cat.prototype = new Animal() except Cat.prototype.name is undefined. 考虑使用extend(Animal, Cat)Cat.prototype = new Animal()相同,只是未定义Cat.prototype.name

The above works perfectly, and I have a side question about it for later. 上面的方法很完美,我对此有一个补充问题。

I wanted to take that to the next level and hide Surrogate inside a closure, so I changed the declarations of Surrogate and extend to look like this: 我想将其Surrogate一个新的水平,并将Surrogate隐藏在一个闭包中,因此我更改了Surrogate的声明并extend为如下所示:

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

Now when I run the script it fails on the first log statement: 现在,当我运行脚本时,它在第一个日志语句上失败:

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

However, creating another file extend.js with the following contents: 但是,使用以下内容创建另一个文件extend.js

var Surrogate = function () {};

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

And changing the declaration of extend in the main script to var extend = require('./extend'); 并将主脚本中的extend声明更改为var extend = require('./extend'); works, and Surrogate is hidden as expected. 起作用,并且Surrogate按预期隐藏。

For the main question: As far as I know node and other CommonJS systems just wrap modules in a closure function like I was originally attempting to do. 对于主要问题:据我所知,节点和其他CommonJS系统只是将模块包装在闭包函数中,就像我最初尝试做的那样。 Why does the module version work but my version with closures doesn't? 为什么模块版本有效,但是带有闭包的版本却无效?

For the side question mentioned above: I was surprised by Sub.prototype.constructor = Sub . 对于上述附带问题: Sub.prototype.constructor = Sub使我感到惊讶。 I thought that it should be Sub.prototype.constructor = Base but that causes the last logging statement to log false . 我以为应该是Sub.prototype.constructor = Base但是这会导致最后一个日志记录语句记录为false I guess I have already answered the question for myself, but I thought that constructor was a property on the constructed object, not the prototype. 我想我已经为我自己回答了这个问题,但是我认为constructor是构造对象的属性,而不是原型的属性。 Is it the other way around? 反过来吗?

UPDATE 更新

I just tried this with AMD using a module called extend defined as follows: 我刚刚使用称为extend的模块对AMD进行了尝试,定义如下:

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

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

It works perfectly fine. 它工作得很好。 I feel like I am overlooking something extremely simple here... why does this work fine in module systems but not in plain closures? 我感觉好像在这里忽略了一个非常简单的事情……为什么这在模块系统中可以正常工作,而在普通闭包中却不能工作? I have tested all versions (plain, closures, and modules) in node.js, Chrome, and Firefox. 我已经在node.js,Chrome和Firefox中测试了所有版本(纯文本,闭包和模块)。

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

should be 应该

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

(I just appended () to it to execute the function.) (我只是将()附加到其上以执行功能。)

or if you want to guard against the possibility that Surrogate might get corrupted(somethign might mess with its constructor function - making it do something): 或者,如果您想防止代理人被损坏的可能性(某些东西可能会破坏其构造函数-使它起作用):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM