【发布时间】:2015-07-13 16:58:54
【问题描述】:
我在下面所做的是否是一种合理的方法,允许回调在对象原型中定义的函数上运行,这样范围是正确的?
我一直在努力设置this 值的正确方法,当对象的原型方法是响应可能源自AJAX 请求或单击绑定或其他的回调的方法时。
这是一个简化的注释版本:
// everything is inside an object which provides the namespace for the app
var namespace = {
// a fairly vanilla object creation routing, which uses the prototype
// approach for defining the functions on the object
newObj : function(params) {
var MyObj = function(params) {
this.property = params.property
};
MyObj.prototype = namespace.ObjPrototype;
return new MyObj(params);
},
// the prototype itself, which defines 2 related functions
ObjPrototype : {
// The first is called to do some form of asynchronous operation
// In this case it is an ajax call
doAsync: function (params) {
$.ajax({
type: "get",
url: params.url,
data: params.data,
dataType: params.datatype,
success: namespace.objClosure(this, "asyncSuccess", ["data"]),
});
// the final line above is the key here - it asks a function (below)
// for a closure around "this", which will in turn run the
// function "asyncSuccess" (defined next) with the argument "data"
},
// This is the actual callback that I want to run. But we can't
// pass this.asyncSuccess to the ajax function above, because the
// scope at execution time is all wrong
asyncSuccess : function(params) {
this.property = params.data;
},
},
// This is the bit I sort of invented, to help me around this problem.
// It returns a function which provides a closure around the object
// and when that returned function is run it inspects the requested
// arguments, and maps them to the values in the JS default
// "arguments" variable to build a parameters object which is then
// passed to the function on the object
objClosure : function(obj, fn, args) {
return function() {
if (args) {
var params = {};
for (var i = 0; i < args.length; i++) {
params[args[i]] = arguments[i];
}
obj[fn](params);
} else {
obj[fn]();
}
}
}
}
现在,显然实际的目标回调 MyObj.asyncSuccess 需要知道它将获得一个 params 对象,以及它将是什么结构,并且该知识必须由调用函数 MyObj.doAsync 共享,否则这个看起来效果不错。
我的问题是——我完全疯了吗?我是否错过了一些明显的东西,可以以更简单/不那么复杂的方式为我解决这个问题?到了这个阶段,我是不是离兔子洞太远了?
我已经阅读了很多关于 SO 的问题,它们都解决了我的部分问题,但我似乎还没有深入了解普遍接受的解决方案。我不可能是唯一一个想要这样做的人:)
编辑
我已接受以下答案,但您也需要阅读所有 cmets 才能将其结合在一起。感谢大家的帮助!
【问题讨论】:
-
你应该看看 Function.bind。 (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…)
-
这看起来很有用,谢谢。我可能需要更深入地研究文档,但我不确定如何让 bind() 获取任意数量的参数。如果您执行 fn.bind(obj, arguments),该函数会接收一个包含 JS 默认“参数”对象的参数,而不是将其解压缩到函数期望的许多实际参数中。如果这是有道理的。所以你不能在一个像
fn(arg1, arg2, arg3)这样的函数上使用它 -
当你想为你的调用“展开”参数时,如果你想摆脱数组的问题,请使用 Function.apply(参见 mdn)。我这里做了一个小例子:jsbin.com/feyuwogobi/1使用jsbin之类的快速测试此类问题。
-
魔术!这正是我所追求的。
标签: javascript jquery ajax closures prototypal-inheritance