读李战的悟透JavaScript的一点理解--深入了解预编译

向大师致敬!以前虽然看过,但是不求甚解,最近开始痛下苦功,有点收获。推荐李战的书 --悟透JavaScript

http://book.douban.com/subject/3271104/   豆瓣上的介绍


在javascript里的全局环境就是一个对象,这个对象是javascript运行环境的根。对于浏览器中的javascript来说,这个根对象就是我们熟知的window对象。对于全局的javascript语句来说,window对象就相当于当前作用域。
当我们写下:

var myname="leadzen" ; //就是定义了window作用域的一个变量myname,而当我们写下:
myname="lead_zen";    //就是定义了window对象的一个属性myname 

在这里,window作用域的一个变量 myname和window对象的一个属性myname几乎等价。

alert(window.myname1); //输出lead_zen
alert(window.myname); //输出leadzen
alert(myname); //输出leadzen

 看另一个例子: 
  

var yourname="真真";
myname="spring";
var interesting="laughing gor";
alert(myname + " like " + yourname);   //输出spring like 真真
changenames();     //直接调用函数,即使函数定义在后面。 函数预编译
function changenames() {
   alert('your old name is ' + yourname);  //输出 your old name is undefined ,因为var yourname,这样yourname赋值undefine
   alert('my old name is ' + myname);     //输出my old name is spring 因为myname是window新添加的一个属性。原型链的问题
                                          //虽然后面有句重设值的语句,但是,还没执行到,所以取全局的值
   //这说明在函数体内也有预编译,对于var定义的变量,会先定义,即使先使用了该变量,也不会报错,只是该值是undefined而已
   alert('interesting ' + interesting);  //输出interesting laughing gor,这说明查找全局作用域(上层作用域) 
                                         //上面两个例子说明,全局变量,无论有无var定义,在函数内都能读取
   alert('perporty of window name' + name );  //向上追溯的问题。最终找到window.name属性,这个为空。所以没有输出
   var yourname = "海琴";
   myname="小莫";                         //全局变量,重设了该值
   alert(myname + " do like " + yourname); //输出小莫 do like 海琴 ,这说明yourname被赋值了
}
alert(myname + " like " + yourname);   //输出小莫 like 真真   海琴只是函数changenames的一个私有变量
alert(window.interesting);             //输出laughing gor,说明全局变量定义是添加或修改了window属性

 这里涉及到函数预编译
       当代码运行进入一个函数时,javascript会创建一个新的作用域,来作为当前作用域的子作用域。然后,将当前全局作用域切换为这个新建的子作用域,开始执行函数逻辑。javascript执行引擎会把此函数内的逻辑代码,当一个代码段单元来分析和执行。       在第一步的预编译分析中,javascript执行引擎将所有定义式函数直接创建为作用域上的函数变量,并将其值初始化为定义的函数代码逻辑,也就是为其建立了可调用的函数变量。而对于所有"var"定义的变量,也会在第一步的预编译中创建起来,并将初始值设为undefined。
看一个特别的例子

function changenames() {
   var yourname = "海琴";
   myname="小莫";                       
}
alert(myname);   //直接报错,为什么呢?因为预编译只是在该函数内有效
//alert(yourname);   //报错,也是同样道理

但是,

function changenames() {
   var yourname = "海琴";
   myname="小莫";                       
}
changenames();
alert(myname);  //输出小莫,因为函数已经执行了,myname是全局变量了,所以,能输出该变量的值

alert(yourname);  //报错,因为yourname是函数体内的私有变量,所以,无法读取。

 随后,javascript开始解释执行代码。当遇到对函数名或变量名的使用时,javascript执行引擎会首先在当前作用域查找函数或变量,如果没有就到上层作用域查找,依次类推。

  因此,用"var"定义的变量只对本作用域有效,尽管此时上层作用域有同名的东西,都与本作用域的"var"变量无关。退出本作用域之后,此"var"消失,回到原来的作用域,该有啥就还有啥,该是谁就还是谁。

额外的思考

            var aa = "dd";
           //aa="dd";
                function bb() {
                    alert(this.aa);    //输出dd,而不是undefined 
                     alert(aa); 
                    var aa = "cc";
                   alert(aa);
                }
                bb();  //输出dd、undefined、cc,即使第一句没有var,aa="dd";调用该函数时,还是输出dd、undefined、cc
                       //这里强调的是this,this指谁呢?window对象 。
          //alert(window.aa);  //输出dd

网上的例子:

   var x = 1, y = z = 0;  
   function add(n) {  
       n = n+1;  
  }  
  
   y = add(x);  
     
   function add(n) {  
      n = n + 3;  
   }  
  
   z = add(x);  

执行完毕后 x, y, z 的值分别是多少? 仔细看的人马上就知道了, x, y 和 z 分别是 1, undefined 和 undefined。 因为调用函数后,没有返回值过来

还一个例子:

  
 

第一个

你可能感兴趣的:(javascript)