[英]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.