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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 00:26:02  来源:igfitidea点击:

JavaScript inheritance: when constructor has arguments

javascriptinheritanceprototype-programming

提问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.prototypean object that inherits from A.prototype, without executing the Aconstructor, 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.createmethod 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 Bsince invoking the constructor of Acan't be done. This is due to the parameters for the constructor being unknown before new Bis executed. You need a dummy constructor function to construct a prototype for Bthat 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 Bset up, you need to ensure to call the constructor of Ain 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 Bby calling new B(x, y).

您现在应该可以B通过调用实例化new B(x, y)

For a complete same including parameter validation in Asee 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 constructorproperty does not influence the inheritance hierarchy for which the prototypeproperty is responsible. If you want to have the named constructor contained in the constructorproperty 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.prototypeyou'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 instanceoffollows up the whole prototype chain of band tries to find a matching prototype object for A.prototypeor B.prototype(in the other call). The b.constructorprototype does refers to the function that was used to define the instances prototype. In case you wonder why it does not point to protoCreatorthis is because its prototype was overwritten with A.prototypeduring the creation of B.prototype. The extended definition as show in the updated examplefixes this constructorproperty to point to a more appropriate (because probably more expected) function.

不同输出的原因是instanceof跟踪整个原型链b并尝试为A.prototypeor找到匹配的原型对象B.prototype(在另一个调用中)。该b.constructor原型确实是指用于定义实例原型的功能。如果你想知道为什么它不指向protoCreatorthis 是因为它的原型A.prototype在创建B.prototype. 更新示例中显示的扩展定义将此constructor属性修复为指向更合适(因为可能更符合预期)的函数。

For daily use, I'd recommend to discard the idea of using the constructorproperty of instances entirely. Instead do use instanceofsince 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 binherits 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.createisn'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.jsfile which is loaded only for IE8 and below via conditional comments.

这可以放置在一个ie8.js文件中,该文件仅通过条件注释为 IE8 及以下加载。