超级骨干

IT技术 javascript inheritance backbone.js
2021-02-22 13:30:22

当我覆盖 a 的clone()方法时Backbone.Model,有没有办法从我的植入中调用这个覆盖的方法?像这样的东西:

var MyModel = Backbone.Model.extend({
    clone: function(){
        super.clone();//calling the original clone method
    }
})
6个回答

你会想要使用:

Backbone.Model.prototype.clone.call(this);

这将使用(当前模型)的上下文调用原始clone()方法Backbone.Modelthis

来自Backbone 文档

简要介绍 super:JavaScript 没有提供调用 super 的简单方法——定义在原型链更高层的同名函数。如果您覆盖了一个核心函数,如 set 或 save,并且您想调用父对象的实现,则必须显式调用它。

var Note = Backbone.Model.extend({
 set: function(attributes, options) {
 Backbone.Model.prototype.set.apply(this, arguments);
 ...
 }    
});
@MikaelLepistö 看到问题stackoverflow.com/questions/1986896/...
2021-05-08 13:30:22
这不适用于完整的原型链。如果直接超类的原型不包含该方法,则会出现异常。
2021-05-12 13:30:22
Backbone 文档似乎建议例如 Backbone.Model.prototype.set.apply(this, arguments); 使用prototype.func_name.apply(...) 和prototype.func_name.call(...) 有什么区别?
2021-05-13 13:30:22

您还可以使用作为__super__对父类原型的引用属性:

var MyModel = Backbone.Model.extend({
  clone: function(){
    MyModel.__super__.clone.call(this);
  }
});
@MauvisLedford是您的示例代码正确的还是应该.set..clone.对OP的使用情况?
2021-04-25 13:30:22
@JasonM 不,this.constructor不能保证是MyModel,如果MyModel用作父类,它会导致堆栈溢出
2021-04-25 13:30:22
关于这个答案的一点背景:__super__是对父级原型的引用,每次扩展 Backbone 模型、集合、路由器或视图时,Backbone 框架都会创建该原型。虽然它不是标准属性,但它确实可以跨浏览器工作,因为它的框架生成了。然而,即使是 Backbone 官方文档也没有提到这一点并说使用Backbone.Model.prototype.set.call(this, attributes, options);方法。不过,两者似乎都运行良好。
2021-04-30 13:30:22
我的只是一个不相关的例子。这将是Backbone.Model.prototype.clone.call(this, attributes, options);在他的案件。
2021-05-03 13:30:22
你也可以使用:this.constructor.__super__
2021-05-21 13:30:22

Josh Nielsen为此找到了一个优雅的解决方案,它隐藏了很多丑陋之处。

只需将此代码段添加到您的应用程序即可扩展 Backbone 的模型:

Backbone.Model.prototype._super = function(funcName){
    return this.constructor.prototype[funcName].apply(this, _.rest(arguments));
}

然后像这样使用它:

Model = Backbone.model.extend({
    set: function(arg){
        // your code here

        // call the super class function
        this._super('set', arg);
    }
});
我在下面的回答解决了具有多个继承级别的问题,
2021-04-26 13:30:22
这仅在只有一级实现 A.foo -> B.foo 时才有效,在 A.foo -> B.foo -> C.foo 的情况下,由于 B 的 this 引用自身,您将获得堆栈溢出
2021-05-11 13:30:22

根据 geek_dave 和 charlysisto 给出的答案,我编写了此代码以this._super(funcName, ...)在具有多个继承级别的类中添加支持。它在我的代码中运行良好。

Backbone.View.prototype._super = Backbone.Model.prototype._super = function(funcName) {
        // Find the scope of the caller.
        var scope = null;
        var scan = this.__proto__;
        search: while (scope == null && scan != null) {
            var names = Object.getOwnPropertyNames(scan);
            for (var i = 0; i < names.length; i++) {
                if (scan[names[i]] === arguments.callee.caller) {
                    scope = scan;
                    break search;
                }
            }
            scan = scan.constructor.__super__;
        }
        return scan.constructor.__super__[funcName].apply(this, _.rest(arguments));
    };

一年后,我修复了一些错误并使事情变得更快。下面是我现在使用的代码。

var superCache = {};

// Hack "super" functionality into backbone. 
Backbone.View.prototype._superFn = Backbone.Model.prototype._superFn = function(funcName, _caller) {
    var caller = _caller == null ? arguments.callee.caller : _caller;
    // Find the scope of the caller.
    var scope = null;
    var scan = this.__proto__;
    var className = scan.constructor.className;
    if (className != null) {
        var result = superCache[className + ":" + funcName];
        if (result != null) {
            for (var i = 0; i < result.length; i++) {
                if (result[i].caller === caller) {
                    return result[i].fn;
                }
            }
        }
    }
    search: while (scope == null && scan != null) {
        var names = Object.getOwnPropertyNames(scan);
        for (var i = 0; i < names.length; i++) {
            if (scan[names[i]] === caller) {
                scope = scan;
                break search;
            }
        }
        scan = scan.constructor.__super__;
    }
    var result = scan.constructor.__super__[funcName];
    if (className != null) {
        var entry = superCache[className + ":" + funcName];
        if (entry == null) {
            entry = [];
            superCache[className + ":" + funcName] = entry;
        }
        entry.push({
                caller: caller,
                fn: result
            });
    }
    return result;
};

Backbone.View.prototype._super = Backbone.Model.prototype._super = function(funcName) {
        var args = new Array(arguments.length - 1);
        for (var i = 0; i < args.length; i++) {
            args[i] = arguments[i + 1];
        }
        return this._superFn(funcName, arguments.callee.caller).apply(this, args);
    };

然后给出这个代码:

var A = Backbone.Model.extend({ 
 //   className: "A",
    go1: function() { console.log("A1"); },  
    go2: function() { console.log("A2"); },  
    });

var B = A.extend({ 
 //   className: "B",
    go2: function() { this._super("go2"); console.log("B2"); },  
    });

var C = B.extend({ 
 //   className: "C",
    go1: function() { this._super("go1"); console.log("C1"); },
    go2: function() { this._super("go2"); console.log("C2"); }  
    });

var c = new C();
c.go1();
c.go2();

控制台中的输出是这样的:

A1
C1
A2
B2
C2

有趣的是,类 C 调用this._super("go1")扫描类层次结构,直到它在类 A 中被命中。其他解决方案不这样做。

PS 取消注释className类定义条目以启用_super查找的缓存(假设这些类名在应用程序中是唯一的。)

我希望我能不止一次支持这个答案。我在互联网上找到的关于 super 的第一个合理描述。这个概念总是让我感到困惑,它与标准 JavaScript 完全不同......
2021-05-02 13:30:22

如果你只想调用 this._super(); 不将函数名称作为参数传递

Backbone.Controller.prototype._super = function(){
    var fn = Backbone.Controller.prototype._super.caller, funcName;

    $.each(this, function (propName, prop) {
        if (prop == fn) {
            funcName = propName;
        }
    });

    return this.constructor.__super__[funcName].apply(this, _.rest(arguments));
}

最好使用这个插件:https : //github.com/lukasolson/Backbone-Super