Javascript 如何从javascript中的子类调用父方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11854958/
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
How to call a parent method from child class in javascript?
提问by YemSalat
I've spent the last couple of hours trying to find a solution to my problem but it seems to be hopeless.
我花了最后几个小时试图找到我的问题的解决方案,但似乎没有希望。
Basically I need to know how to call a parent method from a child class. All the stuff that I've tried so far ends up in either not working or over-writing the parent method.
基本上我需要知道如何从子类调用父方法。到目前为止,我尝试过的所有东西最终要么不起作用,要么覆盖了父方法。
I am using the following code to set up OOP in javascript:
我正在使用以下代码在 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);
I need to call the parent's method first and then add some more stuff to it in the child class.
我需要先调用父类的方法,然后在子类中向它添加更多的东西。
In most OOP languages that would be as simple as calling parent.myMethod()
But I really cant grasp how its done in javascript.
在大多数 OOP 语言中,就像调用一样简单parent.myMethod()
但我真的无法理解它是如何在 javascript 中完成的。
Any help is much appreciated, thank you!
非常感谢任何帮助,谢谢!
回答by YemSalat
Here's how its done: ParentClass.prototype.myMethod();
这是它的完成方式: ParentClass.prototype.myMethod();
Or if you want to call it in the context of the current instance, you can do:
ParentClass.prototype.myMethod.call(this)
或者如果你想在当前实例的上下文中调用它,你可以这样做:
ParentClass.prototype.myMethod.call(this)
Same goes for calling a parent method from child class with arguments:
ParentClass.prototype.myMethod.call(this, arg1, arg2, ..)
* Hint: use apply()
instead of call()
to pass arguments as an array.
从带有参数的子类调用父方法也是如此:
ParentClass.prototype.myMethod.call(this, arg1, arg2, ..)
*提示:使用apply()
而不是call()
将参数作为数组传递。
回答by Dmytro Medvid
ES6 style allows you to use new features, such as super
keyword. super
keyword it's all about parent class context, when you are using ES6 classes syntax. As a very simple example, checkout:
ES6 样式允许您使用新功能,例如super
关键字。super
当您使用 ES6 类语法时,关键字都是关于父类上下文的。作为一个非常简单的例子,结帐:
class Foo {
static classMethod() {
return 'hello';
}
}
class Bar extends Foo {
static classMethod() {
return super.classMethod() + ', too';
}
}
Bar.classMethod(); // 'hello, too'
Also, you can use super
to call parent constructor:
此外,您可以使用super
调用父构造函数:
class Foo {}
class Bar extends Foo {
constructor(num) {
let tmp = num * 2; // OK
this.num = num; // ReferenceError
super();
this.num = num; // OK
}
}
And of course you can use it to access parent class properties super.prop
.
So, use ES6 and be happy.
当然,您可以使用它来访问父类属性super.prop
。所以,使用 ES6 并快乐起来。
回答by Redu
Well in order to do this, you are not limited with the Class
abstraction of ES6. Accessing the parent constructor's prototype methods is possible through the __proto__
property (I am pretty sure there will be fellow JS coders to complain that it's depreciated) which is depreciated but at the same time discovered that it is actually an essential tool for sub-classing needs (especially for the Array sub-classing needs though). So while the __proto__
property is still available in all major JS engines that i know, ES6 introduced the Object.getPrototypeOf()
functionality on top of it. The super()
tool in the Class
abstraction is a syntactical sugar of this.
为了做到这一点,您不受Class
ES6 抽象的限制。可以通过__proto__
属性访问父构造函数的原型方法(我很确定会有其他 JS 编码人员抱怨它已贬值),该属性已贬值,但同时发现它实际上是满足子类需求的重要工具(尤其是对于 Array 子分类需要)。因此,虽然该__proto__
属性在我知道的所有主要 JS 引擎中仍然可用,但 ES6Object.getPrototypeOf()
在其之上引入了该功能。抽象中的super()
工具Class
是它的语法糖。
So in case you don't have access to the parent constructor's name and don't want to use the Class
abstraction you may still do as follows;
因此,如果您无权访问父构造函数的名称并且不想使用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);
}
}
回答by weeger
In case of multiple inheritance level, this function can be used as a super() method in other languages. Here is a demo fiddle, with some tests, you can use it like this, inside your method use : call_base(this, 'method_name', arguments);
在多继承级别的情况下,此函数可以用作其他语言中的 super() 方法。这是一个演示小提琴,有一些测试,你可以像这样使用它,在你的方法中使用:call_base(this, 'method_name', arguments);
It make use of quite recent ES functions, an compatibility with older browsers is not guarantee. Tested in IE11, FF29, CH35.
它使用了相当新的 ES 功能,不能保证与旧浏览器的兼容性。在 IE11、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);
}
}
回答by Alessandro
How about something based on Douglas Crockford idea:
基于道格拉斯·克罗克福德(Douglas 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
回答by CaptureWiz
Here's a nice way for child objects to have access to parent properties and methods using JavaScript's prototype chain, and it's compatible with Internet Explorer. JavaScript searches the prototype chain for methods and we want the child's prototype chain to looks like this:
这是使用 JavaScript 的原型链让子对象访问父属性和方法的好方法,并且它与 Internet Explorer 兼容。JavaScript 在原型链中搜索方法,我们希望子代的原型链看起来像这样:
Child instance -> Child's prototype (with Child methods) -> Parent's prototype (with Parent methods) -> Object prototype -> null
子实例-> 子的原型(带子方法)-> 父的原型(带父方法)-> 对象原型-> null
The child methods can also call shadowed parent methods, as shown at the three asterisks *** below.
子方法也可以调用隐藏的父方法,如下面的三个星号 *** 所示。
Here's how:
就是这样:
//Parent constructor
function ParentConstructor(firstName){
//add parent properties:
this.parentProperty = firstName;
}
//add 2 Parent methods:
ParentConstructor.prototype.parentMethod = function(argument){
console.log(
"Parent says: argument=" + argument +
", parentProperty=" + this.parentProperty +
", childProperty=" + this.childProperty
);
};
ParentConstructor.prototype.commonMethod = function(argument){
console.log("Hello from Parent! argument=" + argument);
};
//Child constructor
function ChildConstructor(firstName, lastName){
//first add parent's properties
ParentConstructor.call(this, firstName);
//now add child's properties:
this.childProperty = lastName;
}
//insert Parent's methods into Child's prototype chain
var rCopyParentProto = Object.create(ParentConstructor.prototype);
rCopyParentProto.constructor = ChildConstructor;
ChildConstructor.prototype = rCopyParentProto;
//add 2 Child methods:
ChildConstructor.prototype.childMethod = function(argument){
console.log(
"Child says: argument=" + argument +
", parentProperty=" + this.parentProperty +
", childProperty=" + this.childProperty
);
};
ChildConstructor.prototype.commonMethod = function(argument){
console.log("Hello from Child! argument=" + argument);
// *** call Parent's version of common method
ParentConstructor.prototype.commonMethod(argument);
};
//create an instance of Child
var child_1 = new ChildConstructor('Albert', 'Einstein');
//call Child method
child_1.childMethod('do child method');
//call Parent method
child_1.parentMethod('do parent method');
//call common method
child_1.commonMethod('do common method');
回答by ZzZombo
There is a much easier and more compact solution for multilevel prototype lookup, but it requires Proxy
support. Usage: SUPER(<instance>).<method>(<args>)
, for example, assuming two classes A
and B extends A
with method m
: SUPER(new B).m()
.
对于多级原型查找,有一个更简单、更紧凑的解决方案,但它需要Proxy
支持。用法:SUPER(<instance>).<method>(<args>)
例如,假设有两个类A
并B extends A
使用方法m
: SUPER(new B).m()
。
function SUPER(instance) {
return new Proxy(instance, {
get(target, prop) {
return Object.getPrototypeOf(Object.getPrototypeOf(target))[prop].bind(target);
}
});
}
回答by StefansArya
While you can call the parent method by the prototype of the parent, you will need to pass the current child instance for using call
, apply
, or bind
method. The bind
method will create a new function so I doesn't recommend that if you care for performance except it only called once.
虽然你可以通过父的原型调用父类的方法,则需要通过当前子实例使用call
,apply
或bind
方法。该bind
方法将创建一个新函数,因此如果您关心性能,我不建议您使用它,除非它只调用一次。
As an alternative you can replace the child method and put the parent method on the instance while calling the original child method.
作为替代方法,您可以在调用原始子方法时替换子方法并将父方法放在实例上。
function proxy(context, parent){
var proto = parent.prototype;
var list = Object.getOwnPropertyNames(proto);
var child = {};
for(var i=0; i<list.length; i++){
var key = list[i];
// Create only when child have similar method name
if(context[key] !== proto[key]){
child[key] = context[key];
context[key] = function(){
context.super = proto[key];
return child[key].apply(context, arguments);
}
}
}
}
// ========= The usage would be like this ==========
class Parent {
first = "Home";
constructor(){
console.log('Parent created');
}
add(arg){
return this.first + ", Parent "+arg;
}
}
class Child extends Parent{
constructor(b){
super();
proxy(this, Parent);
console.log('Child created');
}
// Comment this to call method from parent only
add(arg){
return this.super(arg) + ", Child "+arg;
}
}
var family = new Child();
console.log(family.add('B'));