当我覆盖 Backbone.Model
的 clone()
方法时,有没有办法从我的植入中调用这个被覆盖的方法?像这样的东西:
var MyModel = Backbone.Model.extend({
clone: function(){
super.clone();//calling the original clone method
}
})
你会想要使用:
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);
...
}
});
您还可以使用 __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.
?
Backbone.Model.prototype.clone.call(this, attributes, options);
。
this.constructor
不能保证是 MyModel
,如果将 MyModel
用作父类,它会导致堆栈溢出。
乔什尼尔森found an elegant solution for 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);
}
});
根据 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)
不定期副业成功案例分享