Javascript继承调用父的非默认构造函数

时间:2015-10-19 23:53:10

标签: javascript inheritance prototype super default-constructor

我知道用原型继承的经典模式是基于设置构造函数的对象原型。 但是我愿意有可能从派生类构造函数中调用父构造函数,并使用一些在调用之前不可用的参数。

使用super(...)Parent.__init__(...)方法在Java / Python / PHP中完成了这项工作。

然而,在简单的Javascript(不是coffescript或类似的)中,没有办法做到这一点(parent.apply(this,arguments)但没有设置原型)。

经过一些阅读后,我得到了这个解决方案,添加"继承"函数原型的方法。 这只是将super的定义添加到派生函数中,以便根据某些参数初始化原型。

Function.prototype.inherits=function(parent)
{
    var ctor=this;
    var p=Object.create(parent);
    ctor.super=function()
    {
        parent.apply(p,arguments);
    }
    ctor.prototype=p;
}


//testing

function A(x)
{
    this.x=x;
}

function B(y)
{
    B.super(y*2);//Here "super" is available and I can pass parameters. 
    this.y=y;
}
B.inherits(A);//here I define the inheritance


a=new A(3);
b=new B(5);


console.log(a);//returns { x: 3 }
console.log(b);//returns { y: 5 }
console.log(b.x);//returns 10


console.log(a instanceof A);//returns true
console.log(b instanceof B);//returns true

通过这种方式,我得到了我期望的行为。 我的问题是:这个解决方案的缺点是什么?是否有更有效的解决方案来解决同样的问题?这个解决方案是跨浏览器吗?

PS:我自己发明了它:)

编辑:为了避免与其他库的冲突,我可以定义一个像这样的独立函数来完成相同的目标。

function inherits(klass,parent)
{
    var p=Object.create(parent);
    klass.super=function()
    {
        parent.apply(p,arguments);
    }
    klass.prototype=p;
}

在B的定义之后的测试中只需调用

inherits(B,A);

编辑2: 在Moolamaduck考虑之后,我重写了代码以解决共享原型的问题。结果非常简单易用(恕我直言) https://stackoverflow.com/a/33270707/76081

4 个答案:

答案 0 :(得分:1)

一个缺点可能是扩展内置对象(如Function或Array)的原型可能会与页面上运行的第三方脚本发生冲突。如果两个脚本试图覆盖相同的原型,您可能会得到意想不到的结果。

在浏览器兼容性方面,似乎最弱的链接是Object.create,IE 8及更早版本不支持。见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Browser_compatibility

答案 1 :(得分:1)

您似乎正在寻找一种在JavaScript中重新创建经典的面向对象范例的一般模式(包括使用super)。

几年前 John Resig(jQuery的创建者)提出了一组函数,允许您在Javascript中模仿它。

http://ejohn.org/blog/simple-javascript-inheritance/

然而,由于一些原因(包括使用arguments.callee属性),现在这被视为已弃用,但仍可作为良好的基础

已经提出了一些替代arguments.callee属性的改进,包括:

Is John Resig's Javascript inheritance snippet deprecated?

https://codereview.stackexchange.com/questions/30018/improving-on-john-resigs-simple-javascript-inheritance-avoiding-new

如果你正在寻找一种可靠的方法来重新创建JavaScript中的经典面向对象,我会进一步研究John对原始代码的改进(这个人知道他在说什么,这是一个很好的基础)。

答案 2 :(得分:1)

这是一个实现你想要的最小例子(从派生类的构造函数中调用父构造函数):

var Shape = function(sides) {
  this.sides = sides;
};

var Square = function(size) {
  /* Just call the parent constructor function with `this` as context. */
  Shape.call(this, 4);
  this.size = size;
};

/* Set up the prototype chain. Use a shim for `Object.create` if you want. */
Square.prototype = Object.create(Shape.prototype);

这就是它的全部内容:调用父构造函数,将对象构造为上下文,并设置原型链。

您发布的代码中存在一个严重缺陷。也就是说,您使用派生类的 prototype 作为上下文而不是正在构造的对象来调用父构造函数。这意味着父构造函数初始化的成员将在派生类的所有实例的 prototype 上更新,因此所有实例都将更新。这不是你想要的。

说明问题:

Function.prototype.inherits=function(parent)
{
    var ctor=this;
    var p=Object.create(parent);
    ctor.super=function()
    {
        parent.apply(p,arguments);
    }
    ctor.prototype=p;
}


function A(x)
{
    this.x=x;
}

function B(y)
{
    B.super(y*2);
    this.y=y;
}

B.inherits(A);

var b1 = new B(1);
var b2 = new B(2);
alert(b1.x); // displays "4" instead of "2"!

答案 3 :(得分:0)

在Moolamaduck考虑之后,我重写了代码以解决共享原型的问题。 结果非常简单易用(恕我直言)。

以下是测试:

function inherits(ctor,parent)
{
    ctor.prototype=Object.create(parent.prototype);
    ctor._super=function()
    {
        parent.apply(this,arguments);
    }
}


//testing

function A(x)
{
    this.x=x;
};

function B(y)
{
    B._super.call(this,y*2);//Here "_super" is available (after calling inherits) and I can pass parameters to the parent constructor.
    this.y=y;
};
inherits(B,A);// Here we call inherits, after this parent will be available in the B constructor


a=new A(3);
b=new B(5);


console.log(a);//returns A {x: 3}
console.log(b);//returns B {x: 10, y: 5}
console.log(b.x);//returns 2*5=10

console.log(a instanceof A);//returns true
console.log(b instanceof B);//returns true

//post instantiation method definition and inheritance
A.prototype.test=function(){console.log(this.x+1);};
a.test();//returns 3+1=4
b.test();//returns 2*5+1=11



var b1 = new B(1);
var b2 = new B(2);


console.log(b1.x);//returns 2
console.log(b2.x);//returns 4