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

时间:2014-10-27 15:18:17

标签: javascript node.js

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);

所有测试都会导致: ReferenceError:x未定义

有人知道如何在回调中访问'x'作为局部变量吗?

4 个答案:

答案 0 :(得分:10)

事实:当您在第一行中var inner = function() { console.log(x); }时,x未定义。为什么?因为,在inner函数中,没有x的本地声明(可以使用var x = something完成)。然后,运行时将在下一个范围中查找,即全局范围。还没有x的声明,因此x也没有定义。

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

请记住,当您定义inner时,您正在捕获函数关闭内的环境。这意味着,无论x有什么值(在函数的声明中),都将是x变量的可用值,稍后将使用inner函数。您的x未定义的事实只是一个附件,而不是导致不良行为的原因。

所以,当您在任何IIFE中调用inner函数时,x函数声明中引用的innerx的捕获值x 1}}在定义函数时具有值,而不是console.log()现在在函数当前被称为的范围内的值。这就是所谓的词法范围

要解决此问题,您必须将inner函数内的inner值作为参数传递给var inner = function(x) { console.log(x); } // test 1 (function(cb) { var x = 123; cb(x); })(inner); 函数,如下所示:

{{1}}

答案 1 :(得分:3)

在回调中访问本地变量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);

<强>继续

因为JS是词法范围的,所以在匿名函数执行完毕后尝试引用局部变量是不可能的。如果你没有将它作为参数传递给其他地方使用,那么JS会将其视为不可访问的,并且它有资格进行垃圾收集。

答案 2 :(得分:0)

您可以在当前范围内重新定义回调函数:

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);

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

答案 3 :(得分:0)

您是否尝试过使用事件?在匿名函数内发出一个事件,然后在执行逻辑的其他地方的自己的函数中订阅该事件。