js中的作用域

158 阅读2分钟

ES5的作用域

  1. 全局作用域

    全局作用域,就是全局都可以访问的,这个很好理解。

    例如在index.js中写入以下代码

    var a = "a";
    consoel.log(a);//a
    function (){
    	console.log(a);//a
    }
    fn();
    

    这个变量a在全局都可以访问到,它起效的范围是全局,这个就是全局作用域

  2. 函数内作用域

    函数内作用域,即只在本函数内起效

    function fn() {
        var b = "b";
        console.log(b);//b
    }
    fn();
    console.log(b);//b is not defined
    

    b只能在函数fn内被访问到

  3. 弊端

for (var i = 0; i < 10; i++) {

}
console.log(i);//10

直观的感受一下,感觉i是在for里声明的,为什么还会输出来呢?实际上因为ES5没有块级作用域,for循环里的i被泄露到了全局成了全局变量,下面这种情况更为常见

for (var i = 0; i < 10; i++) {
    setTimeout(()=>{
        console.log(i);//10
    },1000*i);
}
console.log('over');

setTimeout将代码段追加到异步任务里,当执行完console.log('over')之后,会去执行异步任务里的console.log(i),而i是全局变量,值为10,所以每次执行setTimeout对应的代码会输出10

ES6的块及作用域

ES6新增了块级作用域。可以简单的理解为一个大括号就是一块,在块内声明的变量只能在块内被访问到。这个时候就需要我们用let或者const来声明变量了。使用let、const和使用var有很大的区别,这里暂时不讨论。

先来看一下怎么使用的

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
    console.log(n); // 10 内层的n
  }
  console.log(n); // 5 当前层的n
}

这里输出n可以看到都是我们期望的值,当然子块可以父块,父块是访问不到子块的。

再看另一个问题

for (let i = 0; i < 10; i++) {
    setTimeout(()=>{
        console.log(i);//0,1,2,3,4,5,6,7,8,9
    },1000*i);
}
console.log('over');

每次执行setTimeout的时候,都传递了一个函数,这个函数创建了一个块,所以每个i都互不影响