超级骨干

当我重写 Backbone.Modelclone()方法时,有没有办法从我的植入中调用这个重写的方法?就像这样:

var MyModel = Backbone.Model.extend({
clone: function(){
super.clone();//calling the original clone method
}
})
46801 次浏览

你可以使用:

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

这将使用 this(当前模型)的上下文从 Backbone.Model调用原来的 clone()方法。

来自 骨干医生:

关于 super 的简要说明: JavaScript 并不提供一种简单的调用方法 Super ー在原型上更高定义的同名函数 如果你覆盖一个核心函数,比如 set,或者 save,你想要 要调用父对象的实现,您必须 明确地称之为。

var Note = Backbone.Model.extend({
set: function(attributes, options) {
Backbone.Model.prototype.set.apply(this, arguments);
...
}
});

我相信您可以缓存原始方法(尽管没有经过测试) :

var MyModel = Backbone.Model.extend({
origclone: Backbone.Model.clone,
clone: function(){
origclone();//calling the original clone method
}
});

您还可以使用 __super__属性,它是对父类原型的引用:

var MyModel = Backbone.Model.extend({
clone: function(){
MyModel.__super__.clone.call(this);
}
});

乔希尼尔森 找到了一个很好的解决方案,这隐藏了很多丑陋。

只需将这个片段添加到你的应用程序中,就可以扩展 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);
}
});

如果只想调用 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

在实例化期间将父类作为选项传递:

BaseModel = Backbone.Model.extend({
initialize: function(attributes, options) {
var self = this;
this.myModel = new MyModel({parent: self});
}
});

然后在 MyModel 中可以像这样调用父方法

Method () ; 请记住,这将在两个对象上创建一个保留循环。因此,要让垃圾收集器完成这项工作,您需要在处理完一个对象后手动销毁其中一个对象上的保留部分。如果您的应用程序是相当大的。我鼓励您更深入地研究分层设置,以便事件可以传递到正确的对象。

Backbone e. _ super. js,摘自我的要点: https://gist.github.com/sarink/a3cf3f08c17691395edf

// Forked/modified from: https://gist.github.com/maxbrunsfeld/1542120
// This method gives you an easier way of calling super when you're using Backbone in plain javascript.
// It lets you avoid writing the constructor's name multiple times.
// You still have to specify the name of the method.
//
// So, instead of having to write:
//
//    var Animal = Backbone.Model.extend({
//        word: "",
//        say: function() {
//            return "I say " + this.word;
//        }
//    });
//    var Cow = Animal.extend({
//        word: "moo",
//        say: function() {
//            return Animal.prototype.say.apply(this, arguments) + "!!!"
//        }
//    });
//
//
// You get to write:
//
//    var Animal = Backbone.Model.extend({
//        word: "",
//        say: function() {
//            return "I say " + this.word;
//        }
//    });
//    var Cow = Animal.extend({
//        word: "moo",
//        say: function() {
//            return this._super("say", arguments) + "!!!"
//        }
//    });


(function(root, factory) {
if (typeof define === "function" && define.amd) {
define(["underscore", "backbone"], function(_, Backbone) {
return factory(_, Backbone);
});
}
else if (typeof exports !== "undefined") {
var _ = require("underscore");
var Backbone = require("backbone");
module.exports = factory(_, Backbone);
}
else {
factory(root._, root.Backbone);
}
}(this, function(_, Backbone) {
"use strict";


// Finds the next object up the prototype chain that has a different implementation of the method.
var findSuper = function(methodName, childObject) {
var object = childObject;
while (object[methodName] === childObject[methodName]) {
object = object.constructor.__super__;
}
return object;
};


var _super = function(methodName) {
// Keep track of how far up the prototype chain we have traversed, in order to handle nested calls to `_super`.
this.__superCallObjects__ || (this.__superCallObjects__ = {});
var currentObject = this.__superCallObjects__[methodName] || this;
var parentObject  = findSuper(methodName, currentObject);
this.__superCallObjects__[methodName] = parentObject;


// If `methodName` is a function, call it with `this` as the context and `args` as the arguments, if it's an object, simply return it.
var args = _.tail(arguments);
var result = (_.isFunction(parentObject[methodName])) ? parentObject[methodName].apply(this, args) : parentObject[methodName];
delete this.__superCallObjects__[methodName];
return result;
};


// Mix in to Backbone classes
_.each(["Model", "Collection", "View", "Router"], function(klass) {
Backbone[klass].prototype._super = _super;
});


return Backbone;
}));

如果你不知道父类到底是什么(多重继承或者你想要一个 helper 函数) ,那么你可以使用以下方法:

var ChildModel = ParentModel.extend({


initialize: function() {
this.__proto__.constructor.__super__.initialize.apply(this, arguments);
// Do child model initialization.
}


});

有助手功能:

function parent(instance) {
return instance.__proto__.constructor.__super__;
};


var ChildModel = ParentModel.extend({


initialize: function() {
parent(this).initialize.apply(this, arguments);
// Do child model initialization.
}


});

下面有2个函数,一个需要你传入函数名,另一个可以“发现”我们想要的超级版本的函数

Discover.Model = Backbone.Model.extend({
_super:function(func) {
var proto = this.constructor.__super__;
if (_.isUndefined(proto[func])) {
throw "Invalid super method: " + func + " does not exist in prototype chain.";
}
return proto[func].apply(this, _.rest(arguments));
},
_superElegant:function() {
t = arguments;
var proto = this.constructor.__super__;
var name;
for (name in this) {
if (this[name] === arguments.callee.caller) {
console.log("FOUND IT " + name);
break;
} else {
console.log("NOT IT " + name);
}
}
if (_.isUndefined(proto[name])) {
throw "Super method for: " + name + " does not exist.";
} else {
console.log("Super method for: " + name + " does exist!");
}
return proto[name].apply(this, arguments);
},
});

根据 geek _ dave 和 charysisto 给出的答案,我编写本文是为了在具有多个继承级别的类中添加 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));
};

一年之后,我修复了一些 bug,并且让事情变得更快了。

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 中命中。其他解决方案不这样做。

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

我会这样做:

ParentClassName.prototype.MethodToInvokeName.apply(this);

举个例子:

Model.prototype.clone.apply(this)