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

时间:2021-09-28 20:25:20
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'作为局部变量吗?

3 个解决方案

#1


7  

Fact: when you do var inner = function() { console.log(x); } in your first line, x is not defined. Why? Because, inside your inner function, there's no local declaration of x (which would be done with 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.

事实:当你做var inner = function(){console.log(x);在第一行中,x未定义。为什么?因为,在你的内部函数中,没有x的局部声明(这将使用var x = something)。然后,运行时将在下一个范围中查找,即全局范围。也没有x的声明,所以x也没有在那里定义。

The only places where there is a variable called x are inside each one of your 4 IIFEs following. But inside the IIFEs, each x is a different variable, in a different scope. So, if what you want is to console.log() the x defined inside each IIFE, you are taking the wrong approach.

唯一存在一个名为x的变量的地方就在你的4个IIFE中的每一个之后。但在IIFE内部,每个x都是一个不同的变量,在不同的范围内。所以,如果你想要的是console.log()在每个IIFE中定义的x,你采取了错误的方法。

Keep in mind that, when you define inner, you are capturing the environment inside the function's closure. 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. The fact that your x there is not defined is only an accessory, and is not what is causing the undesired behavior.

请记住,当您定义inner时,您正在捕获函数闭包内的环境。这意味着,无论x具有什么值(在函数的声明中),将在以后使用内部函数时为x变量的可用值。你的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. This is what is called lexical scope.

所以,当您在任何IIFE中调用内部函数时,内部函数声明中引用的x是x在定义函数时作为值的值的捕获值,而不是x具有的值现在在当前调用函数的范围内。这就是所谓的词法范围。

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:

要解决这个问题,你必须将内部函数中的console.log()值作为参数传递给内部函数,如下所示:

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

#2


3  

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. 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是词法范围的,所以在匿名函数完成执行后尝试引用局部变量是不可能通过任何其他方法。如果你没有将它作为参数传递给其他地方使用,那么JS会将其视为不可访问的,并且它将有资格进行垃圾回收。

#3


0  

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. The use of eval may introduce security, performance, and code quality issues.

如果函数依赖于最初定义范围内的任何内容或者Javascript文件已缩小,则此方法无效。使用eval可能会引入安全性,性能和代码质量问题。

#1


7  

Fact: when you do var inner = function() { console.log(x); } in your first line, x is not defined. Why? Because, inside your inner function, there's no local declaration of x (which would be done with 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.

事实:当你做var inner = function(){console.log(x);在第一行中,x未定义。为什么?因为,在你的内部函数中,没有x的局部声明(这将使用var x = something)。然后,运行时将在下一个范围中查找,即全局范围。也没有x的声明,所以x也没有在那里定义。

The only places where there is a variable called x are inside each one of your 4 IIFEs following. But inside the IIFEs, each x is a different variable, in a different scope. So, if what you want is to console.log() the x defined inside each IIFE, you are taking the wrong approach.

唯一存在一个名为x的变量的地方就在你的4个IIFE中的每一个之后。但在IIFE内部,每个x都是一个不同的变量,在不同的范围内。所以,如果你想要的是console.log()在每个IIFE中定义的x,你采取了错误的方法。

Keep in mind that, when you define inner, you are capturing the environment inside the function's closure. 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. The fact that your x there is not defined is only an accessory, and is not what is causing the undesired behavior.

请记住,当您定义inner时,您正在捕获函数闭包内的环境。这意味着,无论x具有什么值(在函数的声明中),将在以后使用内部函数时为x变量的可用值。你的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. This is what is called lexical scope.

所以,当您在任何IIFE中调用内部函数时,内部函数声明中引用的x是x在定义函数时作为值的值的捕获值,而不是x具有的值现在在当前调用函数的范围内。这就是所谓的词法范围。

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:

要解决这个问题,你必须将内部函数中的console.log()值作为参数传递给内部函数,如下所示:

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

#2


3  

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. 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是词法范围的,所以在匿名函数完成执行后尝试引用局部变量是不可能通过任何其他方法。如果你没有将它作为参数传递给其他地方使用,那么JS会将其视为不可访问的,并且它将有资格进行垃圾回收。

#3


0  

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. The use of eval may introduce security, performance, and code quality issues.

如果函数依赖于最初定义范围内的任何内容或者Javascript文件已缩小,则此方法无效。使用eval可能会引入安全性,性能和代码质量问题。