Javascript 将作用域传递给回调函数/绑定
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5044807/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Passing scope to callback function / binding
提问by Merl
I am attempting to pass function scope to a callback method. The problem I am having is that I am getting object scope, which does not provide me with access to the parameters and local variables in the original function. My understanding of "this" means the current context (whether it be window or some object) in addition tolocally declared variables and parameters. [cite Richard Cornford's excellent work at http://jibbering.com/faq/notes/closures/on "Execution Contexts" section]. I also understand that variables in JavaScript have function scope (that if they are declared inside a function, they are only accessible from within that function).
我试图将函数作用域传递给回调方法。我遇到的问题是我获得了对象作用域,它不能让我访问原始函数中的参数和局部变量。我对“this”的理解是指除了本地声明的变量和参数之外的当前上下文(无论是窗口还是某个对象)。[在http://jibbering.com/faq/notes/closures/的“执行上下文”部分引用 Richard Cornford 的出色工作]。我也明白 JavaScript 中的变量具有函数作用域(如果它们在函数内部声明,则只能从该函数内部访问它们)。
With that understanding, in a new environment, I am trying to code a pattern that I did alot for my previous employer, calling to an asynchronous method, specifying a callback handler and passing my current scope, expecting it to be available in the callback method. I am not finding this to be the case in my current environment. (disclosure: i was using ExtJS in my previous environment... making me feel now like I was a bit too cozy w/ the framework, making assumptions about what was going on).
有了这样的理解,在一个新环境中,我正在尝试编写一个我为前任雇主做过的模式,调用异步方法,指定回调处理程序并传递我的当前范围,期望它在回调方法中可用. 我发现在我当前的环境中情况并非如此。(披露:我在以前的环境中使用 ExtJS ......让我现在觉得我对框架有点太舒服了,对正在发生的事情做出假设)。
My simple test code demonstrates what I am trying to do and what does not work.
我的简单测试代码演示了我想要做什么以及什么不起作用。
function myHandler(data, ctx) {
console.log('myHandler(): bar: ' + bar); // <- prob: bar undefined
console.log(JSON.stringify(data));
}
MySvcWrap = {
doWork: function(p1, callback, scope) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback.call(scope||this,result, scope);
}
}
}
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler, this); // scope object is this
}
lookup();
The problem here is that the 'this' passed to MySvcWrap.doWork is the Window global object in this case. My intention is to pass function's execution context to myHandler.
这里的问题是,在这种情况下,传递给 MySvcWrap.doWork 的“this”是 Window 全局对象。我的意图是将函数的执行上下文传递给 myHandler。
What I have tried. If, instead of 'this', I pass an object, that works, e.g.:
我尝试过的。如果,而不是“this”,我传递一个对象,该对象有效,例如:
function myHandler(data, ctx) {
console.log('myHandler(): this.bar: ' + this.bar); // <- no prob: this.bar
console.log(JSON.stringify(data));
}
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler, {bar: bar}); // scope object is just object
}
I need someone to club me over the head here... when passing 'this' in my first case, of course this is the global scope (I am in a globally defined function)... My problem is that I thought when passing scope that I had access to locally defined variables and parameters w/in that context... Am I rocking my previous understanding of JS?? How to accomplish this task?
我需要有人在这里把我放在头上......在我的第一种情况下传递'this'时,当然这是全局范围(我在一个全局定义的函数中)......我的问题是我在传递时认为在那种情况下,我可以访问本地定义的变量和参数的范围......我是否改变了我以前对 JS 的理解?如何完成这个任务?
采纳答案by Maxym
btw, few words about scopes in your code:
顺便说一句,关于代码中范围的几句话:
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler, this); // this here points to window object and not to the function scope
}
so it is the same as writing:
所以它和写作一样:
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler, window);
}
it is so because you define lookup function globally. inside doWork
function, when you write this
it points to MySvcWrap
object (because that function is defined inside that object).
之所以如此,是因为您全局定义了查找函数。内部doWork
函数,当您编写this
它时指向MySvcWrap
对象(因为该函数是在该对象内部定义的)。
If your callback function has to see bar
variable, it should be defined in the same scope, like that
如果您的回调函数必须查看bar
变量,则应将其定义在相同的范围内,就像这样
MySvcWrap = {
doWork: function(p1, callback, scope) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback.call(scope||this,result, scope);
}
}
}
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang',
function (data, ctx) {
console.log('myHandler(): bar: ' + bar);
console.log(JSON.stringify(data));
},
this); // scope object is this
}
lookup();
in this case you send anonymous function as callback, it is defined inside lookup function so it has access to its local variables; my console shows me in this cae:
在这种情况下,您将匿名函数作为回调发送,它是在查找函数中定义的,因此它可以访问其局部变量;我的控制台在这个 cae 中显示了我:
myHandler(): bar: food
{"colors":["red","green"],"name":"Jones","what":"thang"}
to make it easier to support, you can define myHandler inside lookup function:
为了更容易支持,您可以在查找函数中定义 myHandler :
function lookup() {
var bar = 'food'; // local var
var myHandler = function(data, ctx) {
console.log('myHandler(): bar: ' + bar);
console.log(JSON.stringify(data));
};
MySvcWrap.doWork('thang', myHandler, this); // scope object is this
}
On the other hand, why one function should have access to local variables of another function? Maybe it can be redesigned...
另一方面,为什么一个函数应该可以访问另一个函数的局部变量?也许它可以重新设计...
One more way to make your code working is to use anonymous function, instead of lookup (will work if you just declare and execute that function once):
使您的代码工作的另一种方法是使用匿名函数,而不是查找(如果您只声明并执行一次该函数,它将起作用):
(function() {
var bar = 'food';
function myHandler(data, ctx) {
console.log('myHandler(): bar: ' + bar);
console.log(JSON.stringify(data));
}
MySvcWrap = {
doWork: function(p1, callback, scope) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback.call(scope||this,result, scope);
}
}
}
MySvcWrap.doWork('thang', myHandler, this);
}
)();
result is the same, but no lookup function anymore...
结果是一样的,但没有查找功能了......
And one more idea to make it working... Actually you need to define callback handler in the same scope where bar variable is defined, so it can be done a bit tricky, but just as alternative:
还有一个让它工作的想法......实际上你需要在定义 bar 变量的同一范围内定义回调处理程序,所以它可以完成有点棘手,但作为替代:
function myHandler(bar) { // actually in this case better to call it createHandler
return function(data, ctx) {
console.log('myHandler(): bar: ' + bar);
console.log(JSON.stringify(data));
}
}
MySvcWrap = {
doWork: function(p1, callback, scope) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback.call(scope||this,result, scope);
}
}
}
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler(bar), this); // scope object is this
}
And few resources to read about JavaScript scoping and closure:
关于 JavaScript 范围和闭包的阅读资源很少:
- Explaining JavaScript scope and closures
- Picking up Javascript - Closures and lexical scoping
- JavaScript: Advanced Scoping & Other Puzzles- very nice presentation about topic
回答by leebriggs
The code would work if it was structured like this.
如果代码是这样结构的,它就可以工作。
MySvcWrap = {
doWork: function(p1, callback, scope) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback.call(scope||this,result, scope);
}
}
}
function lookup() {
var bar = 'food'; // local var
function myHandler(data, ctx) {
console.log('myHandler(): bar: ' + bar); // <- prob: bar undefined
console.log(JSON.stringify(data));
}
MySvcWrap.doWork('thang', myHandler, this); // scope object is this
}
lookup();
The myHandler function can access the local variables of lookup as it is enclosed by it, thus a closure.
myHandler 函数可以访问查找的局部变量,因为它被它包围,因此是一个闭包。
I'd probably try to achieve the same result, by structuring the code like this.
我可能会尝试通过构建这样的代码来实现相同的结果。
function myHandler(data, bar, ctx) {
console.log('myHandler(): bar: ' + bar); // <- prob: bar undefined
console.log(JSON.stringify(data));
}
MySvcWrap = {
doWork: function(p1, callback) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback(result);
}
}
}
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler.bind(this, bar)); // callback function is bound to the scope
}
lookup();
Rather than pass the scope, I use bind inside the lookup method. Using bind I can also add the local variables I wish to pass from that scope.
我没有传递作用域,而是在查找方法中使用了 bind。使用 bind 我还可以添加我希望从该作用域传递的局部变量。
Of course as bind isn't available in older browsers, you either need to add it via a framework, or use one of the many little snippets of code that add the method if it doesn't exist.
当然,由于旧版浏览器中没有绑定,因此您要么需要通过框架添加它,要么使用添加该方法的众多小代码片段之一(如果该方法不存在)。
回答by subhaze
I was a bit quick on my first answer and left some gapping wholes as stated by Maxym in the comments below, thanks for informing me :) That's what I get for trying to post quickly before going back to work :P
我的第一个答案有点快,并如 Maxym 在下面的评论中所说的那样留下了一些空白的整体,感谢您通知我 :) 这就是我在回去工作之前尝试快速发布的结果:P
What I was trying to get at in my first answer is if you want to use binding to access variables in function lookup
from function myHandler
(which is outside the scope of lookup
) you would have to not use var
but this
instead.
如果你想使用绑定变量的访问在功能上有什么,我试图让在我的第一个答案是lookup
从功能myHandler
(这是外面的范围lookup
),你必须不使用var
,但this
代替。
Using var
would make it only accessible to lookup's
private scope and any functions nested in it, which is how the other answers have demonstrated (and are probably the best route)
使用var
将使它只能访问lookup's
私有范围和嵌套在其中的任何函数,这就是其他答案所展示的方式(并且可能是最佳路线)
Below is an updated example of how to pass lookup's scope to myHandler leaving myHandler completely out of lookup's scope. Hopefully this will help shed a bit of light on:
下面是如何将查找范围传递给 myHandler 使 myHandler 完全超出查找范围的更新示例。希望这将有助于阐明:
"The problem I am having is that I am getting object scope, which does not provide me with access to the parameters and local variables in the original function."
“我遇到的问题是我正在获取对象范围,这不能让我访问原始函数中的参数和局部变量。”
As stated in the comments about my previous answer this
can get tricky and you can end up adding things to the global
scope if not careful like I did in my first example. :( So I've added a bit of a hack'ish check to see what scope this
is making sure it's not window
for demonstration purposes...
正如关于我之前的答案的评论中所述,this
可能会变得棘手,global
如果像我在第一个示例中那样不小心,您最终可能会向范围添加内容。:(所以我添加了一些hack'ish检查以查看什么范围this
确保它不是window
用于演示目的......
function myHandler(data, ctx) {
console.log('myHandler(): bar: ' + this.bar); // <- must use `this`
console.log('myHandler(): privateBar: ' + this.privateBar); // <- undefined because it's privately scoped
console.log(JSON.stringify(data));
}
MySvcWrap = {
doWork: function(p1, callback, scope) {
var result = {
colors: ['red', 'green'],
name: 'Jones',
what: p1
};
if (callback) {
callback.call(scope || this, result, scope);
}
}
}
function lookup() {
if(this == window) return lookup.call(lookup); // <- my hack'ish check
var privateBar = 'private food'; // private local var
this.bar = 'food'; // public local var
MySvcWrap.doWork('thang', myHandler, this); // scope object is this
}
lookup();
console.log('global space - bar: ' + this.bar);