一步,两步,三步,四步,五六七八九十步

我所理解的javascript中函数的作用域和作用域链

本文为原创,转载请注明出处: cnzt       文章:cnzt-p

 http://www.cnblogs.com/zt-blog/p/6654308.html

写在前面

  一周木有更新了,今天终于攻克了自行车难关,非常开心,特意来一更~ (那些捂嘴偷笑的人我看到你们了快把嘴闭上我会假装没看见)。

  本文内容均基于个人理解,如有不认同,墙裂欢迎留言交流~~~

 

正文

作用域

  简单来说,javascript中有变量和函数的声明/定义,有变量赋值和函数的执行 ,且遵循先声明后执行原则,举个例子:

1 var a = 1;  // 表达式
2 
3 function func(){ a = a + 1; }; // 函数声明
4 
5 func(); // 函数执行

  上面的代码等同于下面这个:

1 var a;  // 变量声明
2 
3 function func(){ a = a + 1; }; // 函数声明
4 
5 a = 1;   //执行变量赋值 
6 func(); // 函数执行  --> a=2

  

  理解了先声明后执行原则之后,再来看作用域部分。简单来说,javascript的作用域分两类,一类是最外层作用域,如javascript标签包裹起来的块,或者常见的包含init()的块,如下:

1 //html文件中 script标签包裹的块
2 <script>
3     ...
4 </script>
5 
6 //外部 javascript文件中最外层的块,一般包含init()
7 function init(){ ... }
8 ...
9 init()

  另一类是当javascript碰到一个function时,这个function内部会形成一个它内部的作用域。如下:

/*相对于函数来说的作用域*/


...
//这里是函数外部作用域
...
function(){
   //这里是函数内部作用域
   // ...   
}

  第一次敲桌子--内部作用域可以访问外部作用域的值,反之行不通!好了,知道了这两类作用域后,再来边举个栗子边梳理作用域这个东西,栗子如下:

 1 var a = 1;
 2 var b;
 3 var c;
 4 function f(){
 5    b = 2;  
 6    var d = 3;
 7    console.log(a);     //1 
 8    console.log(b);     //2
 9    console.log(d);     //3         
10 }
11 f();
12 console.log(a);   //1
13 console.log(b);   //2
14 console.log(c);   //undefined
15 console.log(d);   //报错: d is not defined

 

  上面的栗子已经注释给出了结果,看到输入的结果觉得正常么?(我好像问了句废话。。。)我还是按照先声明后执行的原则来看下,首先,从上到下,声明了变量a,b,c,函数f,接着执行了a=1,执行函数f,这里第二次敲桌子啦敲桌子!!-- 执行f的时候发生了什么呢?不记得的翻上去看下,首次敲桌时说过了函数内部会形成新的内部的作用域。我们来看下这个作用域,首先声明d,然后执行b=2,d=3,console.log(a),第一次敲桌子的时候说了内部作用域可以访问外部作用域的值,so这里a输入为1,接下来b和d都在函数内部赋过值了,所以console.log(b)和console.log(d)分别输出2和3。至此,f已经执行完了(下划线这部分),继续,console.log(a)这里a也已经赋过值会输出1,console.log(b) -- 第三次敲桌子啦!!!--b声明在外部作用域,赋值在f内部作用域,那么这个赋值的结果在外部作用域还生效么?答案显而易见,生效的,输出2(因为外部声明了,这个变量就一直存在,其他地方的赋值对其均有效)。再然后console.log(c) -- 第四次敲桌子!!!!c只是声明了而已,并没有赋值,因此输出undefined。最后console.log(d) -- 第五次敲桌子!!!!!d为啥会报错呢?回头看首次敲桌时是怎么说的,“反之行不通”,即:函数外部不能访问其内部定义的变量!再回来看d,d只是在f内部定义了,而外部并没有权限访问它,所以这次报错d is not defined...

  /*注意区分undefined 和 d is not defined,一个未赋值,一个根本未声明过。*/ 

 

作用域链

  看上面栗子中的5,7,8行,分别用到了a和b两个变量,这两个变量在f中声明了么?并没有,那为什么还能输出正确的值呢?作用域链就在这时候登场了。f中找不到相应的变量时,向上(外部)一层一层寻找直到最外层,找到则引用,找不到则报错 -- 就是这么简单!

  

思考题

 1 var a = 10;
 2 var b = 5;
 3 function f(){
 4     console.log(a);
 5     var a = 20;
 6     console.log(a);
 7     var d = 30;
 8     var ff  = function(){a++; b++; d++; console.log(a); console.log(b); console.log(d);}
 9     return ff;
10 }    
11 
12 var c = f();
13 c();
14 f()();
15 c();

好好想想这个思考题,注意return的部分,三思而后F12哦~~~

 

本文完。

 

posted @ 2017-04-01 01:54  cnzt  阅读(701)  评论(0编辑  收藏  举报