今天一个同事看到John Resig 的Pro JavaScript Techniques这本书上的37页上有一段关于闭包的javascript代码,怎么调试都运行不正确,于是和他一起研究了一下,代码是这样的:
// Create a new user object that accepts an object of properties function User( properties ) { // Iterate through the properties of the object, and make sure // that it's properly scoped (as discussed previously) for ( var i in properties ) { (function(){ //using this here is wrong 这里用this是错误的,因为这时this的作用域是匿名函数的 // Create a new getter for the property this[ "get" + i ] = function() { //这里用properties[i]也是错误的,因为properties[i]作用域是在闭包的外面 return properties[i]; }; // Create a new setter for the property this[ "set" + i ] = function(val) { properties[i] = val; }; })(); } } // Create a new user object instance and pass in an object of // properties to seed it with var user = new User({ name: "Bob", age: 44 }); // Just note that the name property does not exist, as it's private // within the properties object alert( user.name == null ); // However, we're able to access its value using the new getname() // method, that was dynamically generated alert( user.getname() == "Bob" ); // Finally, we can see that it's possible to set and get the age using // the newly generated functions user.setage( 22 ); alert( user.getage() == 22 );
这段代码应该是有几处错误的,如红色字体所示,this的作用域是匿名函数的;另一处是properties[i],它的scope是匿名函数外面,所以,代码执行将会不正确。
经过一番调试,应该写成这样:
function User( properties ) { //这里一定要声明一个变量来指向当前的instance var objthis = this; for ( var i in properties ) { (function(){ //在闭包内,t每次都是新的,而 properties[i] 的值是for里面的 var t = properties[i]; objthis[ "get" + i ] = function() {return t;}; objthis[ "set" + i ] = function(val) {t = val;}; })(); } } //测试代码 var user = new User({ name: "Bob", age: 44 }); alert( user.getname()); alert( user.getage()); user.setname("Mike"); alert( user.getname()); alert( user.getage()); user.setage( 22 ); alert( user.getname()); alert( user.getage());
这样,代码就是按预想的执行了。 希望对闭包的理解有所帮助。