作用域来自于结构化编程中的概念(关于结构化编程,后面我也花专门的时间去讲解),它决定变量的可见范围和生命周期。在JavaScript中作用域完全由函数决定,也就是说在函数内部定义的变量只对这个函数内部可见,而且函数还可以访问到它定义处外部的作用域,这样的层级关系,我们称之为“作用域链”。例如下面的代码:
1 var a = "我在函数外部"; 2 3 function func() { 4 var b = "我在函数内部"; 5 console.log(a, b); 6 } 7 8 func(); 9 //运行结果 10 我在函数外部 我在函数内部 11 12 console.log(b); 13 //运行结果 14 b is not defined
在函数内部访问一个变量,首先会在函数内部查找是否有定义,若有则使用函数内部定义,若没有则继续向函数外部查找,直到达到全局作用域。在JavaScript中,全局作用域就是全局对象,浏览器中对应的是window对象,Node.js中对应的是global对象。全局对象中的所有属性在任何地方都是可见的,有以下三种方式产生全局属性:
1 var a = "1"; //最外部定义的变量 2 3 function func() { 4 b = "2"; //函数内部,不加var关键字定义的变量 5 } 6 7 console.log(b); 8 9 //运行结果 10 2
作用域内部的变量提升:在一个作用域内,声明的变量将会被提升到作用域前面。注意:在最外部声明的变量会被初始化,而在函数内部后声明的变量不会被初始化。示例代码如下:
1 function foo() { 2 console.log(scope); 3 var scope = "我被提升"; //此处声明的变量将会被提升至console之前,并且值为undefined 4 } 5 6 foo() 7 //运行结果如下 8 undefined 9 10 11 function bar() { 12 console.log(outer); 13 } 14 15 var outer = "我在全局作用域中" 16 17 bar(); 18 //运行结果如下 19 我在全局作用域中 20 21 22 function test() { 23 return test1() + 2; 24 } 25 26 function test1() { 27 return 2; 28 } 29 30 test(); 31 //运行结果如下 32 4