简体   繁体   English

访问回调函数中的局部变量

[英]Access local variable inside a callback function

var inner = function() { console.log(x); }

// test 1
(function(cb) { var x = 123; cb(); })(inner);

// test 2
(function(cb) { var x = 123; cb.apply(this); })(inner);

// test 3
(function(cb) { var x = 123; cb.bind(this)(); })(inner);

// test 4
(function(cb) { cb.bind({x: 123})(); })(inner);

All tests result in: ReferenceError: x is not defined 所有测试都会导致:ReferenceError:未定义x

Do someone know how it is possible to access 'x' as a local variable inside the callback? 有人知道如何在回调中访问'x'作为局部变量吗?

Fact: when you do var inner = function() { console.log(x); } 事实:当你做var inner = function() { console.log(x); } var inner = function() { console.log(x); } in your first line, x is not defined. var inner = function() { console.log(x); }在您的第一线, x没有定义。 Why? 为什么? Because, inside your inner function, there's no local declaration of x (which would be done with var x = something ). 因为,在你的inner函数中,没有x的局部声明(这将使用var x = something )。 The runtime will then look up in the next scope, that is the global scope. 然后,运行时将在下一个范围中查找,即全局范围。 There isn't, also, a declaration of x , so x is also not defined there. 也没有x的声明,所以x也没有在那里定义。

The only places where there is a variable called x are inside each one of your 4 IIFEs following. 唯一有一个名为x的变量的地方就在你的4个IIFE中的每一个之后。 But inside the IIFEs, each x is a different variable, in a different scope. 但在IIFE中,每个x都是一个不同的变量,在不同的范围内。 So, if what you want is to console.log() the x defined inside each IIFE, you are taking the wrong approach. 所以,如果你想要的是console.log()在每个IIFE中定义的x ,你采取了错误的方法。

Keep in mind that, when you define inner , you are capturing the environment inside the function's closure. 请记住,当您定义inner ,您正在捕获函数闭包内的环境。 It means that, whatever value could x have there (in the declaration of the function), would be the available value to the x variable later, when the inner function would be used. 这意味着,无论x具有什么值(在函数的声明中),在使用inner函数时,稍后将是x变量的可用值。 The fact that your x there is not defined is only an accessory, and is not what is causing the undesired behavior. 您的x未定义的事实只是一个附件,并不是导致不良行为的原因。

So, what happens is that when you call your inner function inside any of your IIFEs, the x referred to inside the inner function declaration is a captured value of what x had as a value when the function was defined , not the value that x has now in the scope where the function is currently being called . 所以,当您在任何IIFE中调用inner函数时, inner函数声明中引用的xx定义函数时作为值的捕获值,而不是x具有的值现在在当前调用函数的范围内。 This is what is called lexical scope . 这就是所谓的词法范围

To solve this, you would have to pass the value that you want to console.log() inside the inner function as a parameter to the inner function, as so: 要解决这个问题,你必须将inner函数中的console.log()值作为参数传递给inner函数,如下所示:

var inner = function(x) { console.log(x); }
// test 1
(function(cb) { var x = 123; cb(x); })(inner);

The only way to access the local variable x in the callback, is to pass it as an argument: 在回调中访问局部变量x唯一方法是将其作为参数传递:

var inner = function(some_var) { console.log(some_var); }; //logs 123
(function(cb) { var x = 123; cb(x); })(inner);

OR 要么

var inner = function(some_var) { console.log(some_var); }; //logs 123
(function(cb) { var x = 123; cb.apply(this,[x]); })(inner);

OR 要么

var inner = function(some_var) { console.log(some_var); }; //logs 123
(function(cb) { var x = 123; cb.call(this,x); })(inner);

FURTHER 进一步

Because JS is lexically scoped, trying to reference the local variable after the anonymous function has finished executing is impossible by any other means. 因为JS是词法范围的,所以在匿名函数完成执行后尝试引用局部变量是不可能通过任何其他方法。 If you don't pass it as an argument to make it available elsewhere, JS will see it as non-reachable and it will be eligible for garbage collection. 如果你没有将它作为参数传递给其他地方使用,那么JS会将其视为不可访问的,并且它将有资格进行垃圾回收。

You could redefine the callback function in the current scope: 您可以在当前范围中重新定义回调函数:

var inner = function() { console.log(x); }

(function(cb) { var x = 123; eval('cb = ' + cb.toString()); cb(); })(inner);

// or

(function(cb) { var x = 123; eval('(' + cb.toString() + ')')(); })(inner);

This will not work if the function relies on anything in the scope in which it was originally defined or if the Javascript file has been minified. 如果函数依赖于最初定义范围内的任何内容或者Javascript文件已缩小,则此方法无效。 The use of eval may introduce security, performance, and code quality issues. 使用eval可能会带来安全性,性能和代码质量问题。

Have you tried using events? 你尝试过使用过活动吗? Emit an event inside the anonymous function, then subscribe to it in your own function somewhere else that carries out your logic. 在匿名函数中发出一个事件,然后在你自己的函数中订阅它,执行你的逻辑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM