使用 JavaScript 原型调用方法

IT技术 javascript prototype overriding
2021-01-23 11:49:51

如果被覆盖,是否可以从 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
    }
};
6个回答

我不明白你到底想做什么,但通常实现特定于对象的行为是按照以下方式完成的:

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...*/);
}
这仅适用于实例化的对象。如果您想覆盖所有实例怎么办?
2021-03-23 11:49:51
不要在 JS 中使用“类”字样,因为它会造成混淆。JavaScript 中没有类
2021-03-26 11:49:51
对我有用!正是我所需要的。我有 4 个从父级继承的构造函数。其中两个需要覆盖并调用作为其原型的基本构造函数上的方法。这使我能够做到这一点。
2021-04-06 11:49:51
我不明白,我来这里的目的与 markvpc 完全相同。我的意思是,我想要一种“私有”方法,它可以从原型中的其他方法中使用。您的回应迫使我创建一个工厂,我想知道是否有任何方法可以避免这种情况。
2021-04-10 11:49:51
我不明白为什么这有这么多赞成票并被标记为正确。这只会覆盖基类的一个实例的行为,而不是子类的所有实例。因此,这不能回答问题。
2021-04-11 11:49:51

一种方法是保存基本方法,然后从覆盖方法中调用它,就像这样

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

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

        //do something new

    }else{
        return this._do_base();
    }

};
else 子句正在调用和运行 _do_base,它是对prototype.do 的引用。由于没有参数(或状态)改变,代码将再次进入 else,再次调用 _do_base。
2021-03-20 11:49:51
我去过那里:无限递归。
2021-04-03 11:49:51
这将创建无限递归。
2021-04-12 11:49:51
@JohanTidén_do_base存储对之前定义的任何函数的引用。如果没有,那就是undefinedJavaScript 不是——make表达式永远不会像你建议的那样懒惰地计算。现在,如果被继承的原型使用 _do_base 来存储它认为是它的基类型的 实现do,那么你确实有问题。所以,是的,如果使用这种方法,闭包将是一种更好的、继承安全的方式来存储对原始函数实现的引用——尽管这需要使用Function.prototype.call(this).
2021-04-12 11:49:51

恐怕你的例子不像你想的那样奏效。这部分:

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

覆盖定义

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

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

Javascript 中的经典继承形式很笨拙,而且难以掌握。我建议改用 Douglas Crockfords 的简单继承模式。像这样:

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 中处理对象、构造函数和继承的更清晰的方法。您可以在 Crockfords Javascript: The good parts 中阅读更多内容

确实很好,但是您不能真正base_do作为函数调用,因为这样会丢失this原始do方法中的任何绑定所以,基本方法的设置有点复杂,特别是如果你想使用基本对象this而不是子对象来调用它我会建议类似于base_do.apply(me, arguments).
2021-03-25 11:49:51
只是想知道,你为什么不使用varfor base_do这是故意的,如果是,为什么?而且,正如@GiulioPiancastelli 所说,这是否会破坏this内部绑定,base_do()或者该调用是否会this从其调用者那里继承
2021-04-01 11:49:51
@binki 我更新了这个例子。var应该在那里。使用call(or apply) 可以让我们this正确绑定
2021-04-12 11:49:51

我知道这篇文章是 4 年前的,但由于我的 C# 背景,我一直在寻找一种方法来调用基类,而不必指定类名,而是通过子类的属性获取它。所以我对克里斯托夫答案的唯一改变

由此:

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

对此:

this.constructor.prototype.doStuff.call(this /*, args...*/);
不要这样做,this.constructor可能并不总是指向MyClass.
2021-03-29 11:49:51
好吧,它应该,除非有人搞砸了设置继承。'this' 应该总是指向顶级对象,并且它的 'constructor' 属性应该总是指向它自己的构造函数。
2021-04-05 11:49:51

如果您定义这样的函数(使用 OOP)

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

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

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

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

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