Javascript的作用域
一、作用域
几乎所有的语言都有作用域的概念,简单的说,作用域就是变量和函数的可访问范围,即作用域控制在变量和函数的可见性和生命周期。
在Javascript中,引擎、编译器和作用域共同协调完成Javascript的执行过程。
引擎: 从头到尾负责Javascript代码的编译和执行
编译器:负责词法的分析和代码的生成
作用域:负责收集和维护由声明的变量组成的一系列查询,并执行一套非常严格的规则,确定当前执行的代码对这些变量的访问权限
二、事例
2.1 以代码块为范围的作用域
public void Func(){ if(1==1){ string name = 'java'; } console.writeline(name); } Func()
这段代码是会报错的,在以代码块为作用域范围的语言中,{}中的范围就是一个变量的作用域范围。作用name变量的作用域范围在if条件语句中,console.writeline是获取不到name这个变量的,可以改成:
public void Func(){ if(1==1){ string name = 'java'; console.writeline(name); } //console.writeline(name); } Func()
2.2 以函数为范围的作用域
#python def func(): if 1==1: name = 'python' print(name) func()
这段代码是可以正常运行的,虽然name变量的声明在if的缩进内,但是python语言是以函数为作用域范围的。也就是说在函数内部,一个变量已经声明了,那么就能被接下来的代码调用。
三、Javascript的作用域
3.1 Javascript的作用域也是以整个函数为范围的
# 以整个函数为作用域范围 function func(){ if(1==1){ var name = 'Javascript'; } console.log(name); } func()
控制台运行:
3.2 作用域在未被调用之前已经创建
在上述代码中,编译器(浏览器)自上而下解释执行的过程中,作用域就已经明确了,不是等到调用func()函数的时候才创建完成。
3.3 作用域嵌套
引擎从当前的执行作用域开始查找变量,如果找不到,就向上一级继续查找,直至到最外层的全局作用域链,不管最终是否找到了变量,查找过程到到此结束。
name = 'bigberg'; function func(){ var name = 'eric'; function inner(){ var name = 'Sam'; console.log(name); } return inner; } res = func(); res();
就近原则,输出的是Sam。如果把Sam这行注释掉,那结果又是什么呢?
name = 'bigberg'; function func(){ var name = 'eric'; function inner(){ //var name = 'Sam'; console.log(name); } return inner; } res = func(); res();
res()函数看上去是在函数范围之外执行的,输出的应该是bigberg。但是根据3.2所说,函数的作用域范围是在函数被调用之前就确定的了,那么还是就近原则,输出的应该是eric。
那么如果做如下变动:
name = 'bigberg'; function func(){ var name = 'eric'; function inner(){ //var name = 'Sam'; console.log(name); } var name = 'Tom'; return inner; } res = func(); res();
这种情况输出的是什么呢?根据就近原则来找,inner函数中没有name这个变量,那么就往上一层找。在func函数中,编译器在解释执行时,第一次将eric赋值给了name这个变量,接下来又将Tom这个值赋值给了name变量,所以eric被Tom给覆盖了,所以res()的输出结果就应该是:Tom
3.4 Javascript内部局部变量会声明提前
function func(){ console.log(name); var name = 'bigberg'; }
在Javascript中局部变量会被提前找到做这样一个操作,如:
var name = 'bigberg'; var name; name = 'bigberg';
如果变量没有被赋值,那么其就会被默认赋值为undefined。
所以在上面的代码中,func()函数输出的值应该是undefined。虽然name = 'bigberg',但是在console.log(name)执行时,变量name只执行了var name这个操作,其被默认赋值为undefined。