Javascript继承调用parent's的非默认构造函数
Javascript Inheritance calling parent's non default constructor
我知道经典的继承模式是基于设置构造函数的对象原型。然而,我的意愿是有可能从派生类构造函数调用父构造函数,其中一些参数在调用之前不可用。
这在Java/Python/PHP中使用super(...)
或Parent.__init__(...)
方法可以很好地完成。
然而,在纯Javascript(不是coffescript或类似的)没有办法做到这一点(parent.apply(this,arguments)
,但不是它不设置原型)。
经过一些阅读,我得到了这个解决方案,将"继承"方法添加到Function的原型中。这只是将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的考虑,我重新编写了代码,以解决共享原型的问题。结果是非常简单易用和优雅(IMHO)。https://stackoverflow.com/a/33270707/76081
这里有一个最小的例子,它实现了你想要的(从派生类的构造函数中调用父构造函数):
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);
这就是它所要做的:调用父构造函数,将正在构造的对象作为上下文,并建立原型链。
你发布的代码中有一个严重的缺陷。也就是说,使用派生类的原型作为上下文调用父构造函数,而不是正在构造的对象。这意味着父构造函数初始化的成员将在派生类的所有实例的原型上更新,因此所有实例都将被更新。这不是你想要的。
为了说明这个问题:
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"!
一个缺点可能是扩展内置对象(如Function或Array)的原型有可能与在页面上运行的第三方脚本发生冲突。如果两个脚本试图覆盖相同的原型,您可能会得到意想不到的结果。
在浏览器兼容性方面,似乎最薄弱的环节是Object.create
,这在ie8和更早的版本中是不支持的。看到https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create Browser_compatibility
似乎你正在寻找一个通用的模式,其中在JavaScript中重建经典的面向对象范式(包括使用super
)。
几年前John Resig (jQuery的创建者)建议了一组函数,可以让你在Javascript中模拟这个。
http://ejohn.org/blog/simple-javascript-inheritance/然而,由于一些原因(包括使用arguments.callee
属性),现在认为已弃用,但仍然可以作为一个很好的基础。
有一些改进建议取代arguments.callee
属性,包括:
John resign '的Javascript继承代码段已弃用?
https://codereview.stackexchange.com/questions/30018/improving-on-john-resigs-simple-javascript-inheritance-avoiding-new如果你正在寻找一种可靠的方法在JavaScript中重建经典的面向对象,我会进一步研究John的原始代码的改进(这家伙知道他在说什么,这是一个很好的基础)。
经过Moolamaduck的考虑,我重新编写了代码,以解决共享原型的问题。结果是非常简单易用和优雅(IMHO)。
下面是测试:
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
- ES6构造函数返回基类的实例
- 使用Google Visualization动态调用构造函数
- javascript中对象构造函数中的var属性与this.properties
- 理解typescript中的构造函数接口
- 为什么构造函数不是构造函数
- 如果在构造函数中有“返回”,则在 JavaScript 中的新运算符中做了什么
- 拦截对构造函数的调用
- 使用闭包共享构造函数参数
- 文本表示法VS.构造函数,用于在JavaScript中创建对象
- 从js引擎的角度来看闭包和构造函数是如何工作的
- 如何使用此从对象访问构造函数
- Javascript:为什么是构造函数's __proto__属性Empty(){}
- 当一个重要的构造函数参数丢失时应该发生什么
- 具有默认参数值的 ES6 类构造函数上的 NodeJS 错误
- 使用默认值定义构造函数.我这样做对吗?
- 是否可以在JS对象中添加一个默认函数(构造函数)
- Javascript继承调用parent's的非默认构造函数
- 类构造函数angular 2的默认数组值
- 即使当前时间是标准时间,Javascript日期构造函数也默认为夏令时
- ecmascript 6-Javascript中的默认构造函数