JavaScript的作用域一直如一滩浑水一般,包括工作多年的人也不能完全理解它的机制,很多人简单的概括为function内部以及不带function函数中不带有var声明的为局部变量,function外部为全局变量,其实这种看法是一种经验上的区分,所以,本文就是详细的介绍作用域的机制,以及为什么会出现上述这样的情况,帮助各位更好的理解,做到一通百通。
先看如下代码示例:
function a(){
var a=10;
}
a();
console.log(a);
这个非常容易识别,就像之前说的,a属于局部变量,外部不可访问,console.log()输出的结果是a函数体,并非10,因为 var a=10这部分代码是无法被外部访问,我们可以认为是锁死在了函数体内部。
那么再来一个变种:
function a(){
a=10;
}
a();
console.log(a);
这个对于有相当工作经验的人来说,也容易识别,console.log输出的结果是10,但这和第一段代码有明显的区别,a作为全局变量被抛出外部了,代码在执行过程中其实是先把函数体进行了声明提前,之后a(),调用函数的时候,执行函数体内部代码,因为a没有通过var声明,并没有锁死在函数体内部,而是被抛出到外部执行了,就造成了a变量的覆盖,此时输出结果应该是10
我们继续变种:
function a(a){
var a=10;
}
a(20);
console.log(a);
这段代码执行结果是什么?函数体?10?20?在这个变种里面,有3个a,从这里的变种开始,变得有些迷惑了,要搞清楚,要看程序执行的内存图,下图会进行说明:
所以,判断作用域,不能简单的通过变量存在于函数体内部或者外部进行判断,更要深层次的去看到代码在计算机内存中的运行过程,这个例子中,如果有a被抛出到全局,那么在栈空间中,会覆盖掉原本的a值,a在栈空间是无法保存引用类型的值,只能通过16进制数到堆空间进行查找,函数的形参,其实也是声明在函数体内部的变量,但是其优先级要大于在函数体内声明的变量,之所以函数中的变量和全局变量不冲突的根本原因在于,在内存图中,所存储的不在一个空间,通过内存图能够更加清晰的完全理解JavaScript中的作用域,所以console.log()出来的结果是函数体本身。