四句话总结JavaScript作用域

上一篇文章中简单介绍了一下JS作用域,本篇将作进一步探究和总结。

前言:JavaScript的作用域一直以来都是前端开发中比较难以理解的知识点,JavaScript6中新引入了 let 关键字,用于指定变量属于块级作用域,本次先忽略这个点。

第一句话:JavaScript以函数作为作用域(忽略let)

  很多语言如c#,java都是以代码块作为作用域即大括号也是一个作用域,JavaScript却是以函数作为作用域,如果你对python比较了解,理解起来应该很easy。

在c#中下面的代码将直接报错:

 1 public void Func(){
 2     if(1==1){
 3         string name = 'Java';
 4                             
 5     }
 6     console.writeline(name);
 7                         
 8 }
 9 Func()
10  // 报错    

在JavaScript语言中无块级作用域:

1 function Main(){
2     if(1==1){
3         var name = 'seven';
4     }
5     console.log(name);
6 }
7 // 输出: seven

我们先来回忆一下python的作用域(如果不会python可以跳过,不影响后面阅读):

 1 # 情况一:
 2 def func():
 3     if 1 == 1:
 4         name = 'alex'
 5     print(name)
 6 func()
 7 # 成功
 8 
 9 # 情况二:
10 def func():
11     if 1 == 1:
12         name = 'alex'
13     print(name)
14     
15 func()
16 print(name)
17 # // 报错

 

再来看看JavaScript采用函数作用域:

1 function Main(){
2     var innerValue = 'seven';
3 }
4  
5 Main();
6  
7 console.log(innerValue);
8  
9 // 报错:Uncaught ReferenceError: innerValue is not defined

  在JavaScript中每个函数作为一个作用域,在外部无法访问内部作用域中的变量。console.log(innerValue)访问函数Main()中的变量肯定是不行的。

第二句话:JavaScript函数的作用域在函数未被调用之前,已经创建

  在JavaScript中如果不创建(声明)变量,直接去使用,则报错:

1 console.log(x);
2 VM199:1 Uncaught ReferenceError: x is not defined(…)

  JavaScript中如果创建值而不赋值,则该值为 undefined,如:

1 var num;
2 console.log(num);
3 
4 //undefined

     了解了这个看看下面这个函数:

1 function func(){
2     if(1==1){
3         var name = 'alex';
4     }
5     console.log(name);
6 }

  在浏览器中直接输入这个函数会得到undefined,而不是报错,就说明变量name在函数调用之前就创建(声明)了,但没有被赋值。

 

第三句话:函数的作用域存在作用域链,并且也是在被调用之前创建

 1  1 <script>
 2  2     x = "alex";
 3  3     function func() {
 4  4         var x = "eric";
 5  5         function inner() {
 6  6             var x = "tony";
 7  7             console.log(x);
 8  8         }
 9  9         inner();
10 10     }
11 11     func();
12 12 </script>

输出结果是tony。

如上述代码则出现三个作用域组成的作用域链,如果出现作用域链后,那么寻找变量时候就会出现顺序,对于上述实例:

当执行console.log(xo)时,其寻找顺序为根据作用域链从内到外的优先级寻找,如果内层没有就逐步向上找,直到没找到抛出异常。

 

 练习题1:

 1 x = "alex";
 2 function func() {
 3     var x = "eric";
 4     function inner() {
 5         console.log(x);
 6     }
 7     return inner;
 8 }
 9 var res = func();
10 res();

结果:eric

上述代码,在函数被调用之前作用域链已经存在:

  • 全局作用域 -> func函数作用域 -> inner函数作用域

当执行【ret();】时,由于其代指的是inner函数,此函数的作用域链在执行之前已经被定义为:全局作用域 -> Func函数作用域 -> inner函数作用域,所以,在执行【ret();】时,会根据已经存在的作用域链去寻找变量。

练习题2:

 1 x = "alex";
 2 function func() {
 3     var x = "eric";
 4     function inner() {
 5         console.log(x);
 6     }
 7     var x = 'tony';
 8     return inner;
 9 }
10 var res = func();
11 res();

结果:tony

第四句话: 函数内局部变量 声明提前

1 function func(){
2     console.log(xo);
3     var xo = 'alex';
4 } 
5       
6 func();
7 // undefined

上述代码,不报错而是输出 undefined,其原因是:JavaScript的函数在被执行之前,会将其中的变量全部声明,而不赋值。所以,相当于上述实例中,函数在“预编译”时,已经执行了var xo;所以上述代码中输出的是undefined。

 

posted @ 2016-11-25 11:39  ZingpLiu  阅读(342)  评论(0编辑  收藏  举报
/* 登录到博客园之后,打开博客园的后台管理,切换到“设置”选项卡,将上面的代码,粘贴到 “页脚HTML代码” 区保存即可。 */