超级骨干

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

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

你会想要使用:

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

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

来自Backbone文档 :

除了super之外,JavaScript并没有提供一个简单的方法来调用super–在原型链上定义更高的相同名称的函数。 如果你重写一个像set或save这样的核心函数,并且你想调用父对象的实现,你必须明确地调用它。

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

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

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

乔希尼尔森find了一个优雅的解决scheme ,这掩盖了许多丑陋。

只需将此代码片段添加到您的应用程序即可扩展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

根据geek_dave和charlysisto给出的答案,我写了这个在具有多级inheritance的类中添加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中碰到它。其他解决scheme不会执行此操作。

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

我相信你可以caching原来的方法(虽然没有testing):

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

backbone._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; })); 

如果你不知道父类是什么(多重inheritance或者你想要一个辅助函数),那么你可以使用下面的代码:

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

辅助function:

 function parent(instance) { return instance.__proto__.constructor.__super__; }; var ChildModel = ParentModel.extend({ initialize: function() { parent(this).initialize.apply(this, arguments); // Do child model initialization. } }); 

在实例化过程中将父类作为选项传递:

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

然后在你的MyModel中,你可以调用这样的父类方法

this.options.parent.method(); 请记住,这会在两个对象上创build一个保留循环。 所以为了让垃圾收集器做到这一点,你需要手动删除其中一个对象的保留。 如果你的应用程序相当大。 我鼓励你更多地关注分层设置,以便事件可以传播到正确的对象。

下面的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); }, }); 

这是我将如何做到这一点:

 ParentClassName.prototype.MethodToInvokeName.apply(this); 

所以对于你的例子这是:

 Model.prototype.clone.apply(this)