四句话总结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。
作者:ZingpLiu
出处:http://www.cnblogs.com/zingp/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。