我花了最后几个小时试图找到解决我问题的方法,但这似乎是没有希望的。
基本上,我需要知道如何从子类中调用父方法。到目前为止,我尝试过的所有工作都以无法工作或覆盖父方法而告终。
我正在使用以下代码在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样式允许您使用新功能,例如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并感到高兴。
为了做到这一点,您不受限于Class
ES6。通过__proto__
属性可以访问父构造函数的原型方法(我很确定会有JS编码员抱怨它已贬值),该属性已经贬值了,但同时发现它实际上是满足子类需求的必要工具(尤其是针对Array子分类的需求)。因此,尽管该__proto__
属性在我所知道的所有主要JS引擎中仍然可用,但ES6Object.getPrototypeOf()
在其之上引入了功能。抽象中的super()
工具Class
就是这种语法。
因此,如果您无权访问父构造函数的名称并且不想使用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);
}
}
在多重继承级别的情况下,此函数可以用作其他语言的super()方法。这是一个演示小提琴,带有一些测试,您可以在方法内部使用这样使用它:call_base(this, 'method_name', arguments);
它利用了最新的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);
}
}
基于道格拉斯·克罗克福德(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
这是子对象使用JavaScript的原型链访问父级属性和方法的一种好方法,并且与Internet Explorer兼容。JavaScript在原型链中搜索方法,我们希望子级的原型链如下所示:
子实例->子原型(带有Child方法)->父模型(带有Parent方法)->对象原型-> null
子方法也可以调用带阴影的父方法,如下面的三个星号***所示。
这是如何做:
//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');
对于多层原型查找,有一个更简单,更紧凑的解决方案,但是需要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);
}
});
}
虽然你可以通过父的原型调用父类的方法,则需要通过当前子实例使用call
,apply
或bind
方法。该bind
方法将创建一个新函数,因此我不建议您在只考虑一次的情况下提高性能。
或者,您可以替换子方法并将父方法放在实例上,同时调用原始子方法。
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'));
文章标签:javascript , methods , oop , parent
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!