如何从JavaScript中的子类调用父方法?
我花了几个小时试图find解决我的问题,但似乎是无望的。
基本上我需要知道如何从一个子类调用父方法。 到目前为止,我所尝试过的所有东西都以不工作或覆盖父方法结束。
我正在使用下面的代码在JavaScript中设置OOP:
// SET UP OOP // surrogate constructor (empty function) function surrogateCtor() {} function extend(base, sub) { // copy the prototype from the base to setup inheritance surrogateCtor.prototype = base.prototype; sub.prototype = new surrogateCtor(); sub.prototype.constructor = sub; } // parent class function ParentObject(name) { this.name = name; } // parent's methods ParentObject.prototype = { myMethod: function(arg) { this.name = arg; } } // child function ChildObject(name) { // call the parent's constructor ParentObject.call(this, name); this.myMethod = function(arg) { // HOW DO I CALL THE PARENT METHOD HERE? // do stuff } } // setup the prototype chain extend(ParentObject, ChildObject);
我需要先调用父类的方法,然后在子类中添加更多的东西。
在大多数的OOP语言中,就像调用parent.myMethod()
一样简单,但我真的不知道如何在JavaScript中完成。
任何帮助非常感谢,谢谢!
以下是它的完成方式: ParentClass.prototype.myMethod();
或者如果你想在当前实例的上下文中调用它,你可以这样做: ParentClass.prototype.myMethod.call(this)
ParentClass.prototype.myMethod.call(this, arg1, arg2, ..)
* 提示:使用apply()
而不是call()
将参数作为数组传递。
ES6风格允许您使用新的function,如super
关键字。 super
关键字是关于父类的上下文,当你使用ES6类的语法。 作为一个非常简单的例子,签出:
class Foo { static classMethod() { return 'hello'; } } class Bar extends Foo { static classMethod() { return super.classMethod() + ', too'; } } Bar.classMethod(); // 'hello, too'
另外,你可以使用super
来调用父构造函数:
class Foo {} class Bar extends Foo { constructor(num) { let tmp = num * 2; // OK this.num = num; // ReferenceError super(); this.num = num; // OK } }
当然,您可以使用它来访问父类属性super.prop
。 所以,使用ES6,并开心。
在多inheritance级别的情况下,这个函数可以用作其他语言的super()方法。 call_base(this, 'method_name', arguments);
这里是一个演示提琴 ,有一些testing,
它使用相当新的ESfunction,与旧版浏览器的兼容性不能保证。 testingIE11,FF29,CH35。
/** * Call super method of the given object and method. * This function create a temporary variable called "_call_base_reference", * to inspect whole inheritance linage. It will be deleted at the end of inspection. * * Usage : Inside your method use call_base(this, 'method_name', arguments); * * @param {object} object The owner object of the method and inheritance linage * @param {string} method The name of the super method to find. * @param {array} args The calls arguments, basically use the "arguments" special variable. * @returns {*} The data returned from the super method. */ function call_base(object, method, args) { // We get base object, first time it will be passed object, // but in case of multiple inheritance, it will be instance of parent objects. var base = object.hasOwnProperty('_call_base_reference') ? object._call_base_reference : object, // We get matching method, from current object, // this is a reference to define super method. object_current_method = base[method], // Temp object wo receive method definition. descriptor = null, // We define super function after founding current position. is_super = false, // Contain output data. output = null; while (base !== undefined) { // Get method info descriptor = Object.getOwnPropertyDescriptor(base, method); if (descriptor !== undefined) { // We search for current object method to define inherited part of chain. if (descriptor.value === object_current_method) { // Further loops will be considered as inherited function. is_super = true; } // We already have found current object method. else if (is_super === true) { // We need to pass original object to apply() as first argument, // this allow to keep original instance definition along all method // inheritance. But we also need to save reference to "base" who // contain parent class, it will be used into this function startup // to begin at the right chain position. object._call_base_reference = base; // Apply super method. output = descriptor.value.apply(object, args); // Property have been used into super function if another // call_base() is launched. Reference is not useful anymore. delete object._call_base_reference; // Job is done. return output; } } // Iterate to the next parent inherited. base = Object.getPrototypeOf(base); } }
如何根据道格拉斯Crockford的想法:
function Shape(){} Shape.prototype.name = 'Shape'; Shape.prototype.toString = function(){ return this.constructor.parent ? this.constructor.parent.toString() + ',' + this.name : this.name; }; function TwoDShape(){} var F = function(){}; F.prototype = Shape.prototype; TwoDShape.prototype = new F(); TwoDShape.prototype.constructor = TwoDShape; TwoDShape.parent = Shape.prototype; TwoDShape.prototype.name = '2D Shape'; var my = new TwoDShape(); console.log(my.toString()); ===> Shape,2D Shape
那么为了做到这一点,你不会受到ES6的Class
抽象的限制。 通过__proto__
属性访问父构造函数的原型方法是可能的(我确信会有其他的JS编码器来抱怨这是贬值),这是贬值,但同时发现它实际上是一个子分类需求的重要工具(特别是对于数组子类的需求,虽然)。 所以虽然__proto__
属性在我所知的所有主streamJS引擎中仍然可用,但ES6在其上引入了Object.getPrototypeOf()
function。 Class
抽象中的super()
工具是这个的语法糖。
因此,如果您无法访问父构造函数的名称并且不想使用Class
抽象,那么您仍然可以执行以下操作:
function ChildObject(name) { // call the parent's constructor ParentObject.call(this, name); this.myMethod = function(arg) { //this.__proto__.__proto__.myMethod.call(this,arg); Object.getPrototypeOf(Object.getPrototypeOf(this)).myMethod.call(this,arg); } }