javascript closure(闭包)的一个示例

By | March 6, 2009

今天一个同事看到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());    

这样,代码就是按预想的执行了。 希望对闭包的理解有所帮助。