读李战的悟透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。 因为调用函数后,没有返回值过来

还一个例子:

<script>  
   alert(typeof addA);  
   addA();  
   function addA() {  
      alert("A executed!");  
   };  
</script>  
<script>  
   alert(typeof addB);  
   addB();    //为什么会是报错呢,因为addB是undefined,如果,var addB ...放在addB()前,那结果正常。
              //也就是预编译的值都是undefined的,你如果执行/调用,肯定报错
   var addB = function() {  
     alert("B executed!");  
   };  
</script> 

第一个 <script> 块执行正常,结果就是弹出 "function" 和 "A executed!" 的对话框。 
那么第二个 <script> 块呢? 执行结果是弹出 "undefined" 的对话框后报 JS 错误,说 addB 不是一个 function。 有点出乎意料?呵呵,其实第一个 script 块中的 addA 一句是函数声明,当然进行了"预编译",但是第二个 script 块中的 addB 一句并非函数声明。只不过在执行这段 <script> 之前对变量进行了"预声明",因此一开始变量addB是存在的,只不过是 undefined 的,调用肯定会出错。


将题目再变化下,如下 

   alert(typeof addB);  
   addB();  
   var addB = function addB() {  
     alert("B executed!");  
   };  
将正常输出 ,结果就是弹出 "function" 和 "B executed!" 的对话框。

再变化一下:

  alert(typeof addB);  
   var addB = "variable";  
   function addB() {  
       alert("function addB");  
   }  
   alert(addB); 
执行结果是"function"和"variable"。 
JS解析器先预定义了 addB 变量为 undefined, 但是 addB 函数覆盖了此变量,因此一开始执行结果是 function,然后 addB 被赋值为 "variable",因此最后执行结果是 "variable",上面的代码即使变为 
 alert(typeof addB);  
   function addB() {  
       alert("function addB");  
   }  
   var addB = "variable";  
   alert(addB); 
这说明JS解析器先预声明变量,再预定义函数。 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值