全部变量拥有全局作用域,局部变量拥有局部作用域(这里注意函数的参数也是局部变量)
1.在函数体内,局部变量的优先级高于同名的全局变量。
我的理解就是当你同时定义了同名的局部变量和全局变量时,函数体内返回的将是局部变量的值。
例如:
var scope="我是全局变量"; function checkscope(){ var scope="我是局部变量"; console.log(scope); } checkscope();
输出:我是局部变量
这里需要注意的是,在声明全局变量时可以省略Var(在函数体内如果不用var声明局部变量那么这个变量将是全局变量,那么,但是声明局部变量时一定要声明,否则容易扰乱全局变量的作用域
scope="我是全局变量"; function checkscope(){ scope="我是局部变量"; console.log(scope); } checkscope(); console.log(scope);
输出:我是局部变量
我是局部变量
按道理第二个输出的应该是全局变量,但由于函数体内声明了同名的全局变量,这里就扰乱了全局变量的作用域。
下面讲一下局部作用域嵌套的情况
var scope="我是全局变量"; function checkscope(){ var scope="我是局部变量"; function nested(){ var scope="嵌套的局部变量"; console.log(scope); } return nested(); } checkscope();
输出:嵌套的局部变量
这个对于后面学到的闭包的理解会很有帮助。
2.函数作用域和函数声明提前
(1)要明确的就是在Javascript中是没有块级作用域的,取而代之的是函数作用域
(2)变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
(3)Javascript函数作用域是指在函数内声明的所有变量在函数体内始终都是可见的。
这是什么意思呢?如果学过别的语言一定觉得很神奇了。在C语言中变量都是要先定义后使用的,而这里并不需要。只要你所使用的变量在函数体内有过定义,使用这个变量是可以在函数体内的任意位置的。这就是JS声明提前的魔力了,意思就是JS会自动将变量的声明提到顶部,举个例子:
var scope="我是全局变量"; function f(){ console.log(scope); var scope="我是局部变量"; console.log(scope); } f();
输出:undefined
我是局部变量
如果不知道声明提前肯定会觉得第一个输出会是“我是全局变量"但实际上,在函数顶部以及声明提前了,局部变量scope已经定义只不过没有赋值,所以为undefined
3.作为属性的变量
JS全局变量是全局对象的属性(这里要注意用var声明的全局变量表示创建的这个属性是不可配置的不可用delete运算符删除),也可以用this关键字引用全局对象,这个是可配置可删除的。
ar truevar=1; fakevar=2; this.fakevar2=3; console.log(delete fakevar); console.log(delete truevar); console.log(delete this.fakevar2);
输出
true
false
true
4.作用域链
明白两点:
1.全局变量在程序中始终有定义
2局部变量在函数体内以及嵌套的函数体内始终有定义。
在书上看到一种容易理解的方法:
把一个局部变量看做是自定义实现的对象的属性。那么每一个函数或者全局函数都有一个作用链域,这个作用域链是一个对象列表或者链表。当查找一个变量x时,从链中的第一个对象查找,有这个属性就使用,没有就继续向下查找,整个作用链域上都没有就抛出引用异常。
在JS的顶层代码中,作用链域组成:
1:定义函数参数和局部变量的对象
2:全局对象
嵌套函数的作用域链:
1.定义外层函数时保存的作用域链
2.调用函数时,创建的新的对象存储局部变量,那么这个对象就保存到1中提到的作用域链中,然后创建一个新的更长的表示函数调用的作用域链。
3.对于嵌套函数,每次调用外部函数,内部函数就会重新定义一遍,就会产生新的作用域链。