JavaScript 继承:当构造函数有参数时
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7533473/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript inheritance: when constructor has arguments
提问by Grace Shao
Using pure JavaScript to do inheritance, this is what I usually do:
使用纯 JavaScript 来做继承,我通常是这样做的:
function A() {}
A.prototype.run = function () {};
function B() {}
B.prototype = new A;
B.prototype.constructor = B;
Since there is no arguments to pass into the constructor, new A has nothing to complain about. Now, I haven't figured out a good way to do inheritance if the constructor has arguments to pass. For example,
由于没有要传递给构造函数的参数,因此 new A 没有什么可抱怨的。现在,如果构造函数有参数要传递,我还没有想出一个很好的方法来进行继承。例如,
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {}
B.prototype = new A;
B.prototype.constructor = B;
I could pass some arbitrary values like:
我可以传递一些任意值,例如:
B.prototype = new A(null, null);
In some cases, I may need to validate x and y in the constructor of A. In some extreme cases, I need throw errors when checking x or y. Then, there is no way for B to inherit from A using new A.
在某些情况下,我可能需要在 A 的构造函数中验证 x 和 y。在某些极端情况下,我需要在检查 x 或 y 时抛出错误。那么,B 无法使用新的 A 从 A 继承。
Any suggestions?
有什么建议?
Thanks!
谢谢!
采纳答案by CMS
Well, if you want to make B.prototype
an object that inherits from A.prototype
, without executing the A
constructor, to avoid all possible side-effects, you could use a dummy constructor to do it, for example:
好吧,如果你想创建B.prototype
一个继承自 的对象A.prototype
,而不执行A
构造函数,以避免所有可能的副作用,你可以使用一个虚拟构造函数来做到这一点,例如:
function tmp() {}
tmp.prototype = A.prototype;
B.prototype = new tmp();
B.prototype.constructor = B;
You could create a function to encapsulate the logic of the creation of this new object, e.g.:
您可以创建一个函数来封装这个新对象的创建逻辑,例如:
function inherit(o) {
function F() {}; // Dummy constructor
F.prototype = o;
return new F();
}
//...
B.prototype = inherit(A.prototype);
B.prototype.constructor = B;
If you target modern browsers, you could use the ECMAScript 5 Object.create
method for the same purpose, e.g.:
如果您的目标是现代浏览器,您可以将 ECMAScript 5Object.create
方法用于相同目的,例如:
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
//..
回答by Augustus Kling
The problem is that you can't easily create a prototype object for B
since invoking the constructor of A
can't be done. This is due to the parameters for the constructor being unknown before new B
is executed. You need a dummy constructor function to construct a prototype for B
that links to A
's prototype.
问题是您不能轻松地为其创建原型对象,B
因为A
无法调用 的构造函数。这是因为构造函数的参数在new B
执行之前是未知的。您需要一个虚拟的构造函数来为指向 的原型的B
链接构造一个A
原型。
B.prototype = (function(parent){
function protoCreator(){};
protoCreator.prototype = parent.prototype;
// Construct an object linking to A.prototype without calling constructor of A
return new protoCreator();
})(A);
Once you've got the prototype object for B
set up, you need to ensure to call the constructor of A
in the constructor of B
.
一旦您获得了要B
设置的原型对象,您需要确保A
在 的构造函数中调用 的构造函数B
。
function B(x, y) {
// Replace arguments by an array with A's arguments in case A and B differ in parameters
A.apply(this, arguments);
}
You should now be able to instantiate B
by calling new B(x, y)
.
您现在应该可以B
通过调用实例化new B(x, y)
。
For a complete same including parameter validation in A
see a jsFiddle.
对于完全相同的包括参数验证,A
请参阅jsFiddle。
In your original code you are setting B.prototype.constructor = B
. I'm not getting why you are doing this. The constructor
property does not influence the inheritance hierarchy for which the prototype
property is responsible. If you want to have the named constructor contained in the constructor
property you'd need to extend the code from above a little:
在您的原始代码中,您正在设置B.prototype.constructor = B
. 我不明白你为什么要这样做。该constructor
属性不会影响该prototype
属性负责的继承层次结构。如果您想在constructor
属性中包含命名构造函数,则需要从上面稍微扩展代码:
// Create child's prototype – Without calling A
B.prototype = (function(parent, child){
function protoCreator(){
this.constructor = child.prototype.constructor
};
protoCreator.prototype = parent.prototype;
return new protoCreator();
})(A, B);
Using the first definition of B.prototype
you'd get the following results:
使用B.prototype
你的第一个定义会得到以下结果:
var b = new B(4, 6);
b.constructor // A
console.info(b instanceof A); // true
console.info(b instanceof B); // true
With the extended version, you'll get:
使用扩展版本,您将获得:
var b = new B(4, 6);
b.constructor // B
console.info(b instanceof A); // true
console.info(b instanceof B); // true
The cause for the different output is that instanceof
follows up the whole prototype chain of b
and tries to find a matching prototype object for A.prototype
or B.prototype
(in the other call). The b.constructor
prototype does refers to the function that was used to define the instances prototype. In case you wonder why it does not point to protoCreator
this is because its prototype was overwritten with A.prototype
during the creation of B.prototype
. The extended definition as show in the updated examplefixes this constructor
property to point to a more appropriate (because probably more expected) function.
不同输出的原因是instanceof
跟踪整个原型链b
并尝试为A.prototype
or找到匹配的原型对象B.prototype
(在另一个调用中)。该b.constructor
原型确实是指用于定义实例原型的功能。如果你想知道为什么它不指向protoCreator
this 是因为它的原型A.prototype
在创建B.prototype
. 更新示例中显示的扩展定义将此constructor
属性修复为指向更合适(因为可能更符合预期)的函数。
For daily use, I'd recommend to discard the idea of using the constructor
property of instances entirely. Instead do use instanceof
since its results are more predictable/expected.
对于日常使用,我建议完全放弃使用constructor
实例属性的想法。而是使用instanceof
它,因为它的结果更可预测/预期。
回答by A K
Although this is an old topic, I thought I'd respond anyway. Two ways to do it:
虽然这是一个老话题,但我想我还是会回答。有两种方法可以做到:
Although the Pseudo Classicalway is the most popular, it has its down sides since it needs to call the parent constructor once in the child constructor and once while inheriting the prototype. Besides, the child's prototype will contain all the properties of the parent constructor which will anyway get overwritten when the child constructor is called. My personal choice is Prototypal Inheritance.
虽然Pseudo Classical方式最受欢迎,但它也有缺点,因为它需要在子构造函数中调用一次父构造函数,在继承原型时调用一次。此外,子构造函数的原型将包含父构造函数的所有属性,当调用子构造函数时,这些属性无论如何都会被覆盖。我个人的选择是Prototypal Inheritance。
1. Pseudo Classical Inheritance:
1.伪经典继承:
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {
A.call(this,x,y);
}
B.prototype = new A();
B.prototype.constructor = B;
2. Prototypal Inheritance:
2.原型继承:
function A(x, y) {}
A.prototype.run = function () {};
function B(x, y) {
A.call(this,x,y);
}
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;
回答by ?ime Vidas
Consider this:
考虑一下:
function B( x, y ) {
var b = Object.create( new A( x, y ) );
// augment b with properties or methods if you want to
return b;
}
And then
接着
var b = new B( 12, 13 );
Now b
inherits from an instance of A
, which in turn inherits from A.prototype
.
现在b
继承自 的实例A
,而该实例又继承自A.prototype
.
Live demo:http://jsfiddle.net/BfFkU/
现场演示:http : //jsfiddle.net/BfFkU/
Object.create
isn't implemented in IE8, but one can easily manually implement it:
Object.create
没有在 IE8 中实现,但可以轻松地手动实现它:
if ( !Object.create ) {
Object.create = function ( o ) {
function F() {}
F.prototype = o;
return new F();
};
}
This can be placed inside a ie8.js
file which is loaded only for IE8 and below via conditional comments.
这可以放置在一个ie8.js
文件中,该文件仅通过条件注释为 IE8 及以下加载。