<script language="javascript">
function User( properties ) {
    //遍历对象属性,确保它作用域正确
    for ( var i in properties ) { (function(which){ var p=i
        //为属性创建获取器
        which[ "get" + i ] = function() {
            return properties[p];
        };
        //为属性创建设置器
        which[ "set" + i ] = function(val) {
            properties[p] = val;
        };
    })(this); }
}
var user = new User({
    name: "Bob",
    age: 44
});
alert( user.name == null );
alert( user.getname() == "Bob" );
user.setage( 22 );
alert( user.getage() == 22 );
</script>那位大哥 仔细讲讲User 函数中which 的作用吗? 
         还有var p=i 去掉 其他的p改为i 怎么结果就不对了呢?
在线等!!!!

解决方案 »

  1.   

    which是匿名内部函数的参数.也就是for循环中i的值
      

  2.   

    用p=i的理由
    执行下面测试   <head> 
        <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> 
        <title> </title> 
        <style>     </style>
        <script>
    function User( properties ) {
        //遍历对象属性,确保它作用域正确
        for ( var i in properties ) { (function(which){ 
             var p=i
            //为属性创建获取器
            which[ "get" + i ] = function() {
                alert(i+"  "+p)
                return properties[p];
            };
            //为属性创建设置器
            which[ "set" + i ] = function(val) {
                properties[p] = val;
            };
        })(this); }
    }
    var user = new User({
        name: "Bob",
        age: 44
    });
    alert(user.getname() == "Bob" )
    /*alert( user.name == null );
     user.getname() == "Bob" 
    user.setage( 22 );
    alert( user.getage() == 22 );*/    window.onload=function(){
    }
        </script>
        </head> 
        <body> 
        <div class="news_dh" id=aaa> 
        <TEXTAREA NAME="mytxt" ROWS="5" COLS="25" WRAP="soft"   ID="Textarea1"> </TEXTAREA>     </div>     </body> 
        </html>
    产生这种现象的原因是闭包
      

  3.   

    如果是闭包第一次执行的时候,p与i不相等。所以,如果不把这个时候的i保存下来,就会丢失掉i
      

  4.   

    不是也许是对的,是说错了...纠正下
    which 是用来绑定事件对象的,这里指向User.
      

  5.   


    <script>
    function User(properties){
      //遍历对象属性,确保它作用域正确
      for (var i in properties){
        (
          function(wis2007){//这个which是闭包传进的参数this,随便你用什么名,例如换成wis2007
    alert(i)//加这句就清楚了
            var p=i
            //为属性创建获取器 <-----说的很清楚了。其实就是给this创建一个方法
            wis2007["get"+i]=function(){
              //之所以要将i赋值给p是闭包要求。
              return properties[p];//properties[p]是当前的属性
              //////////return properties[i];//properties[i]是最后一个属性age了          
            };
            //为属性创建设置器<-----说的很清楚了。其实就是给this创建一个方法
            wis2007["set"+i]=function(val){
              properties[p]= val;
            };
          }
        )(this);
      }
    }var user = new User({
        name: "Bob",
        age: 44
    });alert( 'user.name是null吗?\n\n'+(user.name == null) );
    alert( '用新创建的user.getname()获得的是"Bob"吗?\n\n'+(user.getname() == "Bob") );
    user.setage( 22 );
    alert('用新创建的user.setage()获得的是22吗?\n\n'+ (user.getage() == 22) );</script>
      

  6.   

    在调用user的时候,自动的调用了which。每次调用的时候,执行一次操作。那么for中的i是如何存在的呢?如果你第一次访问user的时候,会由于user设定了name、age两个参数而进行初始化。而i是连续给与赋值的。i保存的永远是最后一个参数的名称所以为了保存第一个i,只好用了p这个变量了。
    function User( properties ) {
        //遍历对象属性,确保它作用域正确
        for ( var i in properties ) { alert(i);(function(which){ var p=i
            //为属性创建获取器
            which[ "get" + i ] = function() {
                alert(i+"  "+p)
                return properties[p];
            };
            //为属性创建设置器
            which[ "set" + i ] = function(val) {
                alert(i+"  "+p)
                properties[p] = val;
            };
        })(this); }
    }
    var user = new User({
        name: "Bob",
        age: 44,
        sex:"man"
    });
    //alert( user );
    alert( user.getname() );
    alert( user.getage() );
    //user.setage( 22 );
      

  7.   

    确实是闭包引起的,我是这样理解的方法function(which)是用来给user添加属性访问器对于properties的每一个属性,方法function(which)都会声明且执行一次,
    其中传递给which的实参是user本身。假设将语句 return properties[p]; 改成 return properties[i];对于第一次迭代 which["get" + i] 语句都会给user添加一个方法user.getname(),这并没有什么疑问,
    但对于这个方法的方法体,解析器只是解析,并不执行,其中的i会是一个变量引用。当迭代完成,匿名方法function(which)的外部变量i的值会是迭代的最后一个属性名,也就是age。
    那么当你调用user.getname()时,依然会返回属性age的值,也就是44.
      

  8.   

    li1229363 大哥,为什么p与i不等呢?
      

  9.   

    toury 大哥  “//之所以要将i赋值给p是闭包要求。” 闭包都有什么要求呢?
      

  10.   

    拷贝下面的代码,最好在IE中运行一下,可进入调试状态,然后F11单步跟踪一下,你就明白了
    <body>
      <div id=aaa></div>
    </body><script>
    function User(properties){
    J++;
    sHTML +="2、当你new一个User()对象的实例 “user”时,User()对象开始初始化;<br>"  ;
      
      var cycleCount=0;//为了解释增加该变量
      for (var i in properties){//遍历对象属性,确保它作用域正确
        cycleCount++
        J++;
        sHTML +=J+"、进入遍历对象属性的循环内;属性名为"+i+"<br>" ; 
        /*************************注意这段代码,是一个立即执行的匿名函数**********************************/    (
          function(wis2007){//这个参数是是闭包传进的参数this,随便你用什么名,例如换成wis2007
            J++;
            sHTML +=J+"、进入立即执行的匿名函数;参数wis2007就是传进的this(this指的是你调用User()的对象,就是刚new出来的user),<br>随便你用什么名,例如换成which<br>" ; 
            
            J++;
            sHTML +=J+"、保存第"+cycleCount+"个属性到变量p("+p+")<br>  (如果不保存,则属性是"+i+")<br>" ;         
            var p=i
            
            J++;
            sHTML +=J+"、为属性创建获取器 <-----说的很清楚了。其实就是给this创建一个get"+i+"方法<br>" ;         
            
            wis2007["get"+i]=function(){
              
              J++;
              sHTML +=J+"、调用创建的user.get"+p+"()方法获取"+p+"的值<br>" ;         
              
              return properties[p];//properties[p]是当前的属性
             ///////return properties[i];//properties[i]是最后一个属性age了          
            };
            
            J++;
            sHTML +=J+"、为属性创建获取器 <-----说的很清楚了。其实就是给this创建一个set"+i+"方法<br>" ;                 wis2007["set"+i]=function(val){
              J++;
              sHTML +=J+"、调用创建的user.set"+p+"()方法设置"+p+"的值<br>" ;         
            
              properties[p]= val;
            };
          }
        )(this);  //参数this指的是你调用User()的对象,就是刚new出来的user;此处将它传参进入匿名函数
        
        /**********************************************************************************************/
        J++;
        sHTML +=J+"、<font color=blue>这里的i值是第"+cycleCount+"个属性"+i+";</font><br>" ;           }
        J++;
        sHTML +=J+"、<font color=red>注意!!这里的i值是"+i+";调用getname方法时,由于i是"+i+",所以return properties[i]就变成return properties['"+i+"']了。<br>   这就是为什么要var p=i的原因了</font><br>" ;         
    }
    debugger
    //为了演示JS执行步骤,加了个DIV
    var sHTML='';
     var J=1//为了解释,增加J变量
     
    sHTML +=J+"、new一个User()对象的实例 “user”,它的参数是{name: \"Bob\", age: 44};<br>"
    var user = new User({
        name: "Bob",
        age: 44
    });J++;
    sHTML +="<br><br>"+J+"、初始化结束,开始使用创建的方法;<br>"  ;alert( 'user.name是null吗?\n\n'+(user.name == null) );
    alert( '用新创建的user.getname()获得的是"Bob"吗?\n\n'+(user.getname() == "Bob") );
    user.setage( 22 );
    alert('用新创建的user.setage()获得的是22吗?\n\n'+ (user.getage() == 22) );document.getElementById("aaa").innerHTML=sHTML;
    </script>
      

  11.   

    另外,对于你一直不明白的var p=i的问题(闭包问题),可以改成如下写法,就不用p=i了:<body>
      <div id=aaa></div>
    </body><script>
    function User(properties){
    J++;
    sHTML +="2、当你new一个User()对象的实例 “user”时,User()对象开始初始化;<br>"  ;
      
      var cycleCount=0;//为了解释增加该变量
      for (var i in properties){//遍历对象属性,确保它作用域正确
        cycleCount++
        J++;
        sHTML +=J+"、进入遍历对象属性的循环内;属性名为"+i+"<br>" ; 
        /*************************注意这段代码,是一个立即执行的匿名函数**********************************/    (
          function(wis2007,p){
            //第一个参数是是闭包传进的参数this,随便你用什么名,例如换成wis2007
            //第二个参数就是for循环中的i.传参进来就可以不用var p=i了,这就解决了闭包的问题。当然参数名可以随便取,只要下面相应的更改就可以了
            J++;
            sHTML +=J+"、进入立即执行的匿名函数;参数wis2007就是传进的this(this指的是你调用User()的对象,就是刚new出来的user),<br>随便你用什么名,例如换成which<br>" ; 
            sHTML +="第二个参数就是for循环中的i,传参进来就可以不用var p=i了,这就解决了闭包的问题。当然参数名可以随便取,只要下面做相应的更改就可以了<br>"        //////////////////////var p=i
            
            J++;
            sHTML +=J+"、为属性创建获取器 <-----说的很清楚了。其实就是给this创建一个get"+p+"方法<br>" ;         
            
            wis2007["get"+i]=function(){
              J++;
              sHTML +=J+"、调用创建的user.get"+p+"()方法获取"+p+"的值<br>" ;         
              
              return properties[p];//properties[p]是当前的属性
            };
            
            J++;
            sHTML +=J+"、为属性创建获取器 <-----说的很清楚了。其实就是给this创建一个set"+p+"方法<br>" ;                 wis2007["set"+i]=function(val){
              J++;
              sHTML +=J+"、调用创建的user.set"+p+"()方法设置"+p+"的值<br>" ;         
            
              properties[p]= val;
            };
          }
        )(this,i);  //参数this指的是你调用User()的对象,就是刚new出来的user;此处将它传参进入匿名函数
        //参数 i是循环的参数i,在这里和this一起传入匿名函数,可解决vai p=i的问题。
        
        /**********************************************************************************************/  }
    }
    debugger
    //为了演示JS执行步骤,加了个DIV
    var sHTML='';
     var J=1//为了解释,增加J变量
     
    sHTML +=J+"、new一个User()对象的实例 “user”,它的参数是{name: \"Bob\", age: 44};<br>"
    var user = new User({
        name: "Bob",
        age: 44
    });J++;
    sHTML +="<br><br>"+J+"、初始化结束,开始使用创建的方法;<br>"  ;alert( 'user.name是null吗?\n\n'+(user.name == null) );
    alert( '用新创建的user.getname()获得的是"Bob"吗?\n\n'+(user.getname() == "Bob") );
    user.setage( 22 );
    alert('用新创建的user.setage()获得的是22吗?\n\n'+ (user.getage() == 22) );document.getElementById("aaa").innerHTML=sHTML;
    </script>
    有关闭包的问题,请自己找本书看看,一句话两句话说不清。呵呵还有另外一个方法我就不写了,累了。哪位有兴趣可以写出来。