作用域和作用域链

138 阅读3分钟

作用域 规定变量能够被访问的范围,离开这个范围的变量不能被访问

作用域就是一个独立的地盘,让变量不会外泄、暴露出去,也就是说作用域最大的用处就是隔离变量,不同作用域下同名的变量不会有冲突

作用域分为

全局作用域

局部作用域

函数作用域

块作用域

全局作用域 全局中声明的变量,任何地方都可以被访问

第一种在最外层函数外面定义的变量拥有全局作用域

    var a = '我是全局的'  // 全局变量
    function fn() {
        console.log(a); // 我是全局的  
    }
    fn()

在函数内未定义直接赋值的变量自动声明为全局作用域

    function fn() {
        a = '未定义直接赋值'  //全局变量
        var b = '内层变量'
    }
    fn()
    console.log(a); // 未定义直接赋值
    console.log(b); // b is not defined

所有window对象的属性拥有全局作用域

全局作用域有个弊端:如果我们写了很多行的JS代码,变量定义都没有用函数包括,那么它们就全部都在全局作用域中,这样就会造成变量的污染,容易引起命名的冲突

因此

为 window对象动态添加的属性默认也是全局的(var) 不推荐

函数中未使用任何关键字声明的变量为全局变量 不推荐

尽可能少的声明全局变量,防止全局变量被污染

函数作用域 在函数内 部声明的变量只能在函数内容部被访问,外部无法直接访问

函数内部被访问,外部无法直接访问

函数的参数也是函数内部的局部变量

函数执行完毕后,函数内部的变量实际就被清空了

    function fn(a,b) {
        // 函数内定义的变量,外部无法访问
        // 函数的参数也是局部变量
        var s = a + b  
        console.log(s);  // 18
    }
    fn(10,8)
    console.log(s);  // s is not defined
    console.log(a);  //a is not defined

块作用域(let,const) ES6带来的新特性,在代码块中声明的语句或变量只在当前语句块中起作用

函数作用域和块级作用域没有直接的关系,函数作用域在ES5和ES6作用完全一样,变量不论是使用var,let,const声明,在外部都是不可以访问的

而块级作用域(let,const),指的就是用{}包裹的代码称为代码块。并且代码块内部用let和const声明的变量外部无法被访问

  let flag = true
  if (flag) {
    let str = 'hello word'
    console.log(str) //hello word
  }
  console.log(str) //str is not defined

经典案例

for (var i = 0; i < 4; i++) {
    setTimeout(function () {
         console.log(i);
    }, 200);
}
//4 4 4 4

使用let形成块级作用域

for (let i = 0; i < 4; i++) {
    setTimeout(function () {
         console.log(i);
    }, 200);
}
//0 1 2 3

作用域链 作用域链的本质 是底层的变量查找机制,函数被执行时,会优先查找当前函数作用域中的变量,如果找不到则会逐级查找父级作用域直到全局作用域,全局找不到 变量返回undefined,函数调用报错

    let a = 20
    function fn() {
        var b = a + 10  // 当前作用域中没有a,所以往上找,a=20 ,所以b=20+10 = 30
        function fn1() {
            var c = 10
            return b + c  //当前作用域中没有b 往上找 b=30 30+10 最终返回40
        }
        // 由于当前作用域中没有d,一直往上找,最终也没有找到d,所以报错 d isnot defined
        console.log(d); 
        return fn1()
    }
    fn()  // 40

子作用域能够访问父作用域中的变量,而父作用域无法访问子作用域中的变量