上一篇文章中简单介绍了一下JS作用域,本篇将作进一步探究和总结。
前言:JavaScript的作用域一直以来都是前端开发中比较难以理解的知识点,JavaScript6中新引入了 let 关键字,用于指定变量属于块级作用域,本次先忽略这个点。
第一句话:JavaScript以函数作为作用域(忽略let)
很多语言如c#,java都是以代码块作为作用域即大括号也是一个作用域,JavaScript却是以函数作为作用域,如果你对python比较了解,理解起来应该很easy。
在c#中下面的代码将直接报错:
public void Func(){
if(==){
string name = 'Java'; }
console.writeline(name); }
Func()
// 报错
在JavaScript语言中无块级作用域:
function Main(){
if(1==1){
var name = 'seven';
}
console.log(name);
}
// 输出: seven
我们先来回忆一下python的作用域(如果不会python可以跳过,不影响后面阅读):
# 情况一:
def func():
if 1 == 1:
name = 'alex'
print(name)
func()
# 成功 # 情况二:
def func():
if 1 == 1:
name = 'alex'
print(name) func()
print(name)
# // 报错
再来看看JavaScript采用函数作用域:
function Main(){
var innerValue = 'seven';
} Main(); console.log(innerValue); // 报错:Uncaught ReferenceError: innerValue is not defined
在JavaScript中每个函数作为一个作用域,在外部无法访问内部作用域中的变量。console.log(innerValue)访问函数Main()中的变量肯定是不行的。
第二句话:JavaScript函数的作用域在函数未被调用之前,已经创建
在JavaScript中如果不创建(声明)变量,直接去使用,则报错:
console.log(x);
VM199:1 Uncaught ReferenceError: x is not defined(…)
JavaScript中如果创建值而不赋值,则该值为 undefined,如:
var num;
console.log(num); //undefined
了解了这个看看下面这个函数:
function func(){
if(1==1){
var name = 'alex';
}
console.log(name);
}
在浏览器中直接输入这个函数会得到undefined,而不是报错,就说明变量name在函数调用之前就创建(声明)了,但没有被赋值。
第三句话:函数的作用域存在作用域链,并且也是在被调用之前创建
1 <script>
2 x = "alex";
3 function func() {
4 var x = "eric";
5 function inner() {
6 var x = "tony";
7 console.log(x);
8 }
9 inner();
10 }
11 func();
12 </script>
输出结果是tony。
如上述代码则出现三个作用域组成的作用域链,如果出现作用域链后,那么寻找变量时候就会出现顺序,对于上述实例:
当执行console.log(xo)时,其寻找顺序为根据作用域链从内到外的优先级寻找,如果内层没有就逐步向上找,直到没找到抛出异常。
练习题1:
x = "alex";
function func() {
var x = "eric";
function inner() {
console.log(x);
}
return inner;
}
var res = func();
res();
结果:eric
上述代码,在函数被调用之前作用域链已经存在:
- 全局作用域 -> func函数作用域 -> inner函数作用域
当执行【ret();】时,由于其代指的是inner函数,此函数的作用域链在执行之前已经被定义为:全局作用域 -> Func函数作用域 -> inner函数作用域,所以,在执行【ret();】时,会根据已经存在的作用域链去寻找变量。
练习题2:
x = "alex";
function func() {
var x = "eric";
function inner() {
console.log(x);
}
var x = 'tony';
return inner;
}
var res = func();
res();
结果:tony
第四句话: 函数内局部变量 声明提前
function func(){
console.log(xo);
var xo = 'alex';
} func();
// undefined
上述代码,不报错而是输出 undefined,其原因是:JavaScript的函数在被执行之前,会将其中的变量全部声明,而不赋值。所以,相当于上述实例中,函数在“预编译”时,已经执行了var xo;所以上述代码中输出的是undefined。