如何在没有闭包的情况下编写共享状态?

时间:2014-09-26 01:31:02

标签: javascript closures

var state = 0;
var interval = setInterval(function() { 
    // Do something depending on state
}, 1000)

因为一切都可以在没有闭包的情况下完成,所以这更像是一种智力练习,因为我无法看到如何在没有闭包的情况下编写这样的东西。我通过引用将状态传递给匿名函数吗? (JavaScript不支持通过引用传递)

4 个答案:

答案 0 :(得分:1)

这是一个不可取的答案,因为当你开始讨论它时,绝对没有不创造封闭的范围;这是关闭是否使用以及如何使用的问题。

Closure只是一个内部范围,它维护对外部范围的引用。

这样说:

/* global */
window.incr_id = 0;
window.tick = 0;

function nextTick () { window.tick += 1; }

window.incr_id = window.setInterval(nextTick, 1000);

这对你来说算是封闭吗?

从技术上讲,全局范围相当于在其他语言中运行Main (),因此nextTick函数保存对外部范围值(window)的引用,导致遍历价值表链,从而形成“封闭”。

您可以尝试类似

的内容
function nextTick () { nextTick.value += 1; }
nextTick.value = 0;

...但是这是否有意义,因为自我引用来自括号之外,因此属于更高的范围?

function nextTick () { arguments.callee.value += 1; }
nextTick.value = 0;

当然,这会阻止您在严格模式下使用此解决方案(如果您希望安全,则应使用此解决方案)。

当然,你可以创建一个不是有问题的函数的闭包,而是创建monad,这样你就可以通过组合函数逐步传递值,而不是依赖于封闭参考......

那里的问题当然是setInterval需要一个功能 因此,无论您返回setInterval哪个函数,最终函数都必须使用闭包引用,无论您的所有应用函数是否都在之前执行。

如果引用一个未在当前函数范围内定义的函数,或者我们只是在谈论标量,那么函数引用是否计为闭包引用?

故事的道德:

window.value = 1;
window.obj.value = 1;

func.value = 0;
function func () { func.value = 1; }

function func () { arguments.callee.value = 1; }

前两个是有效的,如果你愿意承认“窗口”可以被引用而不是一个闭包(暗示,它不能)。

如果您愿意接受以非严格模式运行对您的客户,您的受众以及您的整体健康和福祉不利,那么最后一个可能是有效的。

答案 1 :(得分:1)

你可以在没有闭包的情况下做任何事情。例如,状态可以用指定的方法存储在对象中以“调用函数”。但是,您需要一个不同的setInterval()函数来获取您的方法类型,而不是现在所使用的函数类型。

答案 2 :(得分:0)

您不需要在JavaScript中通过引用传递变量。如果不在闭包内使用var,则会影响较高级var

简单示例:

var state = 0;
var interval = setInterval(function(){ 
  state++; // state increases by one every second
}, 1000);
// should console.log(4)
setTimeout(function(){console.log(state)}, 4500);

如果你这样做了:

var state = 0;
var interval = setInterval(function(){
  var state = 0;
  state++; // state increases by one every second
  // state is 1 every time at this point
  // state outside closure is not affected
}, 1000);
// should console.log(0) - state refers to outside of closure
setTimeout(function(){console.log(state)}, 4500);

在某种意义上,你可以认为JavaScript中的每个变量都是通过引用传递的,甚至没有将它们作为参数传递。实际上,如果你使用变量名作为参数,它将在你传递给它的函数中重新定义,而不会影响更高级别的变量。

将匿名函数作为参数传递,根据具体情况,可能会也可能不会执行任何操作。在setInterval()的情况下,不会将任何内容传递给您传递给它的函数。注意:

var state = 0;
var interval = setInterval(function(arg){
  var state = 0;
  state++; // state increases by one every second
  // state is 1 every time at this point
  // state outside closure is not affected
}, 1000);

相同
var state = 0;
function what(arg){
  var state = 0;
  state++; // state increases by one every second
  // state is 1 every time at this point
  // state outside closure is not affected
}
var interval = setInterval(what, 1000);

所以,实际上该函数没有任何参数传递给setInterval()。您放入function what(){}的任何参数都必须通过setInterval()传递一个参数,该参数不传递任何参数。

检查出来:

function whatever(func){
  // takes function argument like `setInterval()`
  // need to pass it something to have func take an argument
  func("We'll just pass our function this String");
}
whatever(console.log); // now console.log() is passed an argument

因此,您可以看到将函数作为参数的函数决定了作为参数传递的函数传递的参数。

答案 3 :(得分:0)

  

我是否通过引用将状态传递给匿名函数?

是。虽然setInterval在没有"关闭"的情况下非常复杂,但它并不能真正让你通过任何东西。

  

JavaScript不支持通过引用传递

是。我们不会使用对变量的引用,而是使用存储状态的对象。您不必修改闭包变量,而是修改传递的对象。

var state = {
    value: 0
};
state.interval = setInterval(function() { 
    // Do something depending on this.value
}.bind(state), 1000);