当我重写a的clone()
方法时Backbone.Model
,是否可以从植入中调用此重写的方法?像这样:
var MyModel = Backbone.Model.extend({
clone: function(){
super.clone();//calling the original clone method
}
})
当我重写a的clone()
方法时Backbone.Model
,是否可以从植入中调用此重写的方法?像这样:
var MyModel = Backbone.Model.extend({
clone: function(){
super.clone();//calling the original clone method
}
})
Answers:
您将要使用:
Backbone.Model.prototype.clone.call(this);
这将使用(当前模型)的上下文调用原始clone()
方法。Backbone.Model
this
从骨干文档:
除了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);
}
});
__super__
是对Backbone框架每次扩展Backbone模型,集合,路由器或视图时所制作的父级原型的引用。尽管它不是标准属性,但自从其框架生成以来,它确实可以跨浏览器工作。但是,即使是Backbone官方文档也没有提到这一点,而是说使用Backbone.Model.prototype.set.call(this, attributes, options);
方法。不过,两者似乎都可以正常工作。
.set.
是.clone.
对OP的使用情况?
Backbone.Model.prototype.clone.call(this, attributes, options);
他而言。
this.constructor
不能保证是MyModel
,如果MyModel
用作父类,它将导致堆栈溢出。
乔什·尼尔森(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);
}
});
从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
查找缓存。(假设这些类名在应用程序中将是唯一的。)
如果只想调用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
我相信您可以缓存原始方法(尽管未经测试):
var MyModel = Backbone.Model.extend({
origclone: Backbone.Model.clone,
clone: function(){
origclone();//calling the original clone method
}
});
Backbone.Model.prototype.clone
和this.origclone()
。等同于Backbone.Model.prototype.clone.call(this)
。
骨干._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;
}));
如果您不知道父类到底是什么(多重继承或需要帮助函数),则可以使用以下命令:
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.
}
});
在实例化期间将父类作为选项传递:
BaseModel = Backbone.Model.extend({
initialize: function(attributes, options) {
var self = this;
this.myModel = new MyModel({parent: self});
}
});
然后在您的MyModel中,您可以像这样调用父方法
this.options.parent.method(); 请记住,这会在两个对象上创建一个保留周期。因此,要让垃圾收集器完成工作,您需要在完成后手动破坏其中一个对象上的保留。如果您的应用程序很大。我鼓励您更多地研究层次结构,以便事件可以传播到正确的对象。
var self = this
在这种情况下,不需要,因为它不在丢失上下文的回调函数中。
下面的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)