在关闭时保留变量内容的问题

时间:2015-07-31 19:09:29

标签: javascript loops object scope closures

(这个问题与thisthis有关,但那里的答案并没有帮助我弄清楚我的情况有什么问题。)

我正在尝试创建一个可点击元素数组,其中每个元素都绑定到某个对象的单独实例。

我在这里简化了我正在努力解决这个问题的实际代码:

//----------
// Setup part

// SomeObject just holds a number
var SomeObject = function(number) {
	this.number = number;
	
	this.getNumber = function() {
		return this.number;
	};
};

// contains SomeObject(1) through SomeObject(9)
var someArrayContainingObjects = [];
for(var i=1; i<=9; i++)
{
	someArrayContainingObjects.push(new SomeObject(i));
}

//----------
// Problem part
for(var y=0; y<3; y++)
{	
	for(var x=0; x<3; x++)
	{
		var obj = someArrayContainingObjects[y*3 + x]; // Creating new variable in the loop every time explicitly with var statement?
		$("body").append(
			$("<button />")
			.text("Should output ("+obj.getNumber()+")")
			.click(function() {
				alert(obj.getNumber()); // Will always be 9
			})
		);
	}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

我想通过在循环中明确地使用var obj = ...我会创建一个新的上下文/范围/但是我为每个我正在创建的匿名click()回调函数调用它 - 所以当我点击其中一个对象,相应的SomeObject的适当数量是alert() ed,并不总是循环从数组中获取的最后SomeObject的数量。

有人可以向我解释为什么这段代码片段没有按预期工作,以及要使代码正常运行需要更改的内容?

1 个答案:

答案 0 :(得分:1)

To create closure scope in JavaScript you need to invoke a function. In JavaScript we can also invoke functions as soon as you declare them. They are called immediately invoked function expressions

This way you can preserve your x and y values in the scope of the IIFE.

for(var y=0; y<3; y++) {    
  for(var x=0; x<3; x++) {
    (function (x, y) {
      var obj = someArrayContainingObjects[y * 3 + x]
      $("body").append(
        $("<button />")
          .text("Should output ("+obj.getNumber()+")")
          .click(function() {
            alert(obj.getNumber())
          })
      )
    }(x, y))
  }
}

Working codepen

Also, this is a big problem that people encounter when they try to write JavaScript as if it was a class based language. I would try to look into writing JS from a more functional perspective