聊聊js的作用域

170 阅读2分钟

这是我参与8月更文挑战的第10天,活动详情查看:8月更文挑战

前言

在上一篇文章中,我们刚好讲了constlet命令,里面简单说了点作用域的内容。那么就书接上回,再来讲讲js的作用域。

在es6之前,js的作用域是只有全局作用域和函数作用域的。 es6新增了块级作用域。下面来展开说说js的作用域。

全局作用域

全局作用域,顾名思义,就是存在最顶端的作用域,全局都能访问。

var name = '答案cp3'
function getName () {
  console.log(name) // 答案cp3
}
getName()

if(true) {
 console.log(name) // 答案cp3
}

可以看到,在全局作用域声明的变量,不管在哪都能访问的到。

函数作用域

函数作用域,就是存在函数内部的作用域,仅在函数内部能访问。

function getName () {
  var name = '答案cp3'
  return name
}
getName() // 答案cp3
console.log(name) // ''

可以看到,在getName内部声明的变量,无法在外部的作用域访问到。

块级作用域

之所以es6要引入块级作用域,是因为之前的作用域可能会存在以下问题:

  • 变量提升导致变量被覆盖

    var name = '答案cp3'
    function getName () {
     console.log(name)
     var name = 'cp3'
    }
    getName() // undefined
    

    var声明导致变量提升,导致打印出的nameundefined

  • 在for循环中,var声明的变量,在for循环结束后还能继续访问

    for(var i = 0; i < 5; i++) {
      console.log(i) // 0 1 2 3 4 5
    }
    console.log(i) // 5
    

块级作用域,就是限制变量的声明只在这块区域可以访问到。一般是由{}包裹的里面代码块形成块级作用域,比如if语句,while语句,for循环语句, try-catch语句等

另外,块级作用域一般是要配合let, const一起使用。

改写上面的例子:

for(let i = 0; i < 5; i++) {
  console.log(i) // 0 1 2 3 4 5
}
console.log(i) // i is not defined

let声明的 i,只在for循环里面可以访问,for循环结束后无法再访问。

块级作用域之间的变量声明互不影响,内层的声明可以覆盖外层的同名变量。

如代码所示:

if(true) {
  let name = '答案'
  console.log(name) // 答案
}
if(true) {
  let name = 'cp3'
  console.log(name) // cp3
}
if(true) {
  let name = '答案'
  if(true) {
     let name = 'cp3'
     if(true) {
        let name = '答案cp3'
        console.log(name) // 答案cp3
     }
  }
}

补充一点(参考来自阮一峰的块级作用域):

在块级作用域中函数声明(不建议这样写),如果你是在es6的浏览器中运行代码,则函数声明会变量提升,如果是在其它环境运行,则不会变量提升。

// 不建议, 函数声明尽量在全局作用域中声明或者在函数作用域声明
if(true) {
 console.log(fn) // 在es6的浏览器中fn会提升
 function fn() {}
}

块级作用域必须要有{}包裹

总结

以上就是我总结的js的作用域:

  • 全局作用域,全局都能访问的作用域
  • 函数作用域,只存在函数内部的作用域
  • 块级作用域, 只在{}内的代码块访问到的作用域,配合let/const使用,可以避免变量提升和变量污染等问题

感谢你们的阅读。