作用域和作用域链

483 阅读2分钟

作用域

变量的作用域无非两种:全局变量,局部变量。

ES6之前,javascript没有块级作用域,它的作用域是相对函数而言,最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的。

    var outerVar = "outer";
    function fn(){
        console.log(outerVar);// outer
    }
    fn();

for不是函数,可以看到定义的i是全局变量。js函数内的变量值不是在编译的时候就确定的,而是等在运行时期再去寻找的。

for(var i = 1; i < 10; i++){
     //coding
}
console.log(i); //10

ES6,let定义的变量,作用于当前块级。

{
    let name = 'yang'
}
console.log(name)//name is not defined

如果函数内部定义了一个和外部变量相同的变量名称,那么函数内部使用这个变量时,只会获取函数内部所定义的值。

    var outerVar = "outer";
    function fn(){
         var outerVar = 'inner'
        console.log(outerVar);// inner
    }
    fn();

var定义的变量具有提升作用。

    var outerVar = "outer";
    function fn(){
        console.log(outerVar);// undefined
         var outerVar = 'inner'
        console.log(outerVar);// inner
    }
    fn();

函数参数的作用域:

var a = '1'
var b = { age : '2' }
var c = [3]
function start(a,b,c){
    a = '3'
    b = { age : '4'}
    c.push(5)
}
start(a,b,c)
console.log(a,b,c)// 1,{age:'2'},[3,5]

函数进行声明初始化时,参数会形成一个单独的作用域,等到初始化完成,这个作用域会消失。函数的参数的作用域为本函数。

所以,函数的参数初始化时,相当于为它们各自重新声明了一个变量,并且有初始化值。


var a = '1'
var b = { age : '2'}
var c = [3]

然后函数内部改变这些参数的值,相当于函数内部开辟了值为'3','{age:"4"}'的新空间,并把a和b的值分别指向这两个新地址。

a = '3'
b= {age:'4'}

c的情况比较特殊,它是数组,不是赋值的方式,而是push的方式。而且我们知道,数组是在堆中的对象,所以c实质上是一个指向堆的地址,push就是往这个堆里,放进去一个新的数值。所以c.push会改变外面c的值。

如果在函数中,直接用另一个数组赋值给c,相当于函数内部开辟了一个新堆,并且把c指向这个新堆,则不会改变外面的c:

var c = [3]
function start(c){
    c = [4]
}
start(c)
console.log(c)// [3]

作用域链

执行程序时,遇到变量,就会在当前作用域中寻找,找不到,就往上一级作用域找,如果一直找不到,就会返回undefined。