使用 JavaScript 原型调用方法

如果基方法被重写,是否可以从 JavaScript 中的原型方法调用它?

MyClass = function(name){
this.name = name;
this.do = function() {
//do somthing
}
};


MyClass.prototype.do = function() {
if (this.name === 'something') {
//do something new
} else {
//CALL BASE METHOD
}
};
159304 次浏览

我不明白您到底想要做什么,但是通常实现特定于对象的行为是这样做的:

function MyClass(name) {
this.name = name;
}


MyClass.prototype.doStuff = function() {
// generic behaviour
}


var myObj = new MyClass('foo');


var myObjSpecial = new MyClass('bar');
myObjSpecial.doStuff = function() {
// do specialised stuff
// how to call the generic implementation:
MyClass.prototype.doStuff.call(this /*, args...*/);
}

如果我理解正确的话,您希望始终执行 Base 功能,而将其中的一部分留给实现。

您可能会得到“ 模板法”设计模式的帮助。

Base = function() {}
Base.prototype.do = function() {
// .. prologue code
this.impldo();
// epilogue code
}
// note: no impldo implementation for Base!


derived = new Base();
derived.impldo = function() { /* do derived things here safely */ }

一种方法是保存基方法,然后从重写的方法中调用它,像这样

MyClass.prototype._do_base = MyClass.prototype.do;
MyClass.prototype.do = function(){


if (this.name === 'something'){


//do something new


}else{
return this._do_base();
}


};

恐怕你的例子不是你想的那样,这部分:

this.do = function(){ /*do something*/ };

覆盖了... 的定义

MyClass.prototype.do = function(){ /*do something else*/ };

因为新创建的对象已经具有“ do”属性,所以它不会查找原型链。

Javascript 中经典的继承形式是笨拙的,而且很难掌握。我建议使用 Douglas Crocfords 的简单遗传模式。像这样:

function my_class(name) {
return {
name: name,
do: function () { /* do something */ }
};
}


function my_child(name) {
var me = my_class(name);
var base_do = me.do;
me.do = function () {
if (this.name === 'something'){
//do something new
} else {
base_do.call(me);
}
}
return me;
}


var o = my_child("something");
o.do(); // does something new


var u = my_child("something else");
u.do(); // uses base function

在我看来,这是一种在 javascript 中处理对象、构造函数和继承的更清晰的方法。你可以阅读更多的克罗克福德 Javascript: 好的部分

不,您需要给构造函数中的 do 函数和原型中的 do 函数起不同的名称。

我知道这篇文章是4年前的,但是因为我的 C # 背景,我正在寻找一种方法来调用基类,而不必指定类名,而是通过子类上的一个属性来获得它。因此,我唯一的变化 克里斯托弗的回答将是

由此可见:

MyClass.prototype.doStuff.call(this /*, args...*/);

这样说:

this.constructor.prototype.doStuff.call(this /*, args...*/);
function NewClass() {
var self = this;
BaseClass.call(self);          // Set base class


var baseModify = self.modify;  // Get base function
self.modify = function () {
// Override code here
baseModify();
};
}

如果您像这样定义一个函数(使用 OOP)

function Person(){};
Person.prototype.say = function(message){
console.log(message);
}

调用原型函数有两种方法: 1)创建一个实例并调用 object 函数:

var person = new Person();
person.say('hello!');

另一种方法是... 2)直接从原型调用函数:

Person.prototype.say('hello there!');

如果你知道你的超类的名字,你可以这样做:

function Base() {
}


Base.prototype.foo = function() {
console.log('called foo in Base');
}


function Sub() {
}


Sub.prototype = new Base();


Sub.prototype.foo = function() {
console.log('called foo in Sub');
Base.prototype.foo.call(this);
}


var base = new Base();
base.foo();


var sub = new Sub();
sub.foo();

这个会打印出来

called foo in Base
called foo in Sub
called foo in Base

不出所料。

此外,如果您想要 覆盖所有实例而不仅仅是那一个特殊实例,这个实例可能会有所帮助。

function MyClass() {}


MyClass.prototype.myMethod = function() {
alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
MyClass.prototype.myMethod_original.call( this );
alert( "doing override");
};


myObj = new MyClass();
myObj.myMethod();

结果:

doing original
doing override
function MyClass() {}


MyClass.prototype.myMethod = function() {
alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
MyClass.prototype.myMethod_original.call( this );
alert( "doing override");
};


myObj = new MyClass();
myObj.myMethod();

另一种选择:

// shape
var shape = function(type){
this.type = type;
}
shape.prototype.display = function(){
console.log(this.type);
}
// circle
var circle = new shape('circle');
// override
circle.display = function(a,b){
// call implementation of the super class
this.__proto__.display.apply(this,arguments);
}

此解决方案使用 Object.getPrototypeOf

TestA是超级拥有 getName

TestB是一个重写 getName的子代,但是,也有 getBothNames,它调用 getNamesuper版本和 child版本

function TestA() {
this.count = 1;
}
TestA.prototype.constructor = TestA;
TestA.prototype.getName = function ta_gn() {
this.count = 2;
return ' TestA.prototype.getName is called  **';
};


function TestB() {
this.idx = 30;
this.count = 10;
}
TestB.prototype = new TestA();
TestB.prototype.constructor = TestB;
TestB.prototype.getName = function tb_gn() {
return ' TestB.prototype.getName is called ** ';
};


TestB.prototype.getBothNames = function tb_gbn() {
return Object.getPrototypeOf(TestB.prototype).getName.call(this) + this.getName() + ' this object is : ' + JSON.stringify(this);
};


var tb = new TestB();
console.log(tb.getBothNames());

ES5的另一种方法是使用 Object.getPrototypeOf(this)显式地遍历原型链

const speaker = {
speak: () => console.log('the speaker has spoken')
}


const announcingSpeaker = Object.create(speaker, {
speak: {
value: function() {
console.log('Attention please!')
Object.getPrototypeOf(this).speak()
}
}
})


announcingSpeaker.speak()