初学JS小记(一)——变量的作用域

来源:互联网 发布:protobuf c windows 编辑:程序博客网 时间:2024/06/05 16:37

        刚刚开始学习javascript时,其实并没有过多的看过相关方面的书籍,只是稍微了解了其语法和如何定义函数、变量,凭借着自己之前写过java和 c++的经验,开始了我的前端之路。写一些小的项目还基本OK,可是有时候总是踩坑,还半天爬不出来。后来,有空 看了看JavaScrip高级程序设计,才发现其实js跟之前的c++和java还是有很多区别的,很多时候踩坑就是因为不清楚js跟这些语言本质上的区别。在此,我记录下一些看书时候觉得比较有用,但是可能被广大小白同学忽略的问题,希望对大家有帮助。对于有时间的初学朋友,还是推荐能好好的看看《JavaScrip高级程序设计》,必定会有很多的收获。

一、变量的作用域

    1.1无块级作用域

         与大多数语言相同的是,在全局环境中的变量存在与整个程序运行中,在局部作用域中的变量离开其作用域之后,被销毁。不同之处在javascript没有块级作用域。在c或java中,在花括号中定义的变量,离开这对花括号之后,便被销毁。可是,于 javascript讲,在花括号中定义的变量的作用域并不仅仅存在与花括号内。如下:

if (true) {    var hi = "hi";} console.log(hi);

在c或java中,hi在if语句中定义,出了if的作用域就被销毁,在if之外访问hi会引发程序错误,但是,因为js没有块级作用域,所以在if中定义的变量在if语句之外的作用域还 是有效的。所以上述代码在js中是正确的。类似的容易搞错的还有在for循环中定义的变量。如下:

for (var i=1;i<10;i++) {     doSomething(i);} console.log(i);

在for的条件中初始化的变量在for循环之外还是存在的。

    1.2 变量作用域范围 

        通过上述例子,可能有很会好奇在花括号中定义的变量的作用域又到哪里呢?难道在全局范围内有效么? 

      关于这个问题就需要讲到js中的执行环境这个概念。执行环境规定了变量或者函数有权访问的哪些数据。每个执行环境中有一个对应的变量对象,变量对象保存了该环境中定义的变量和函数。

        全局执行环境是最外层的执行环境。在web浏览器中,全局执行环境的对象是window对象。也就是说所有在全局中定义的函数和变量都属window对象的属性和方法。执行环境在改环境中的所有代码执行后,其中的变量和函数被全部销毁(全局执行环境直到应用程序退出才被销毁)。

       每个函数都有自己的执行环境。当函数执行完后,其执行环境被销毁,控制权返回给之前的执行环境。所以,定义的变量的作用域是离定义这个变量最近的函数的执行环境中。如果定义这个变量是在全局范围内,那变量的作用域是全局范围。

 for (var i=1;i<10;i++) {     if(true) {         if(true) {             var hi = "hi"         }     }} console.log(hi); doSomthing(); 
function doSomting () {    if (true) {        for (var i=1;i<10;i++) {            var hello = "hello";        }    }    console.log(hello);}

述代码中,无论hi是在多少个内层花括号中定义的,它在离它最近的执行环境中都是有效的(这里是全局执行环境)。而hello在doSometihng函数中定义,所以,hello在doSomething中都是有效的。

   1.3 作用域链

      当代码在一个环境中执行时,会创建一个作用域链,作用域链就是为了执行环境能有序地访问变量和函数。作用域链最开始是当前代码所在环境中的变量对象。下一个变量对象是包含当前环境的外部环境,就这样一直包含到全局执行环境。所以作用域链的最后一个对象总是全局执行环境中的变量对象。

     在访问变量时,就是从作用域的最前端开始,逐级寻找变量的定义。如下:

var hi = "hi";function sayA () {    var hello = "hello";    function sayB() {        var world = "world";    //    可以访问hello ,hi,world        console.log(hi + "," + hello + ' ' + world);    }    //    可以访问hello ,hi,但是不能访问world    console.log(hi + "," + hello);}

        通过这个小例子,我们可以看出在js中,即使没有通过参数将外部变量传递给函数,但是通过作用域链还是可以访问外部函数中定义的变量。但是外部函数不能访问内部函数定义的变量。因为外部函数的作用域链中不能包含内部函数的变量对象。所以任何函数都能访问全局环境中的变量和函数同时,如果一个变量名在多处被定义,则根据作用域链访问顺序,采用第一个访问到的变量名的定义。 如下:

var a = 9;sayA();function sayA () {    var a = 7;    sayB();    function sayB() {        console.log(a);    }}

打印出 :7

因为sayB先访问自己的变量对象,没有a的定义,再访问sayA的变量对象,找到了a的定义,就不会再继续找了。

原创粉丝点击