作用域的基本介绍

87 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情

前言

JavaScript 的作用域通俗来讲,就是指变量能够被访问到的范围,在 JavaScript 中作用域也分为好几种,ES5 之前只有全局作用域和函数作用域两种。ES6 出现之后,又新增了块级作用域,下面我们就来看下这三种作用域的概念,为闭包的学习打好基础。

1.全局作用域

在编程语言中,不论 Java 也好,JavaScript 也罢,变量一般都会分为全局变量和局部变量两种。那么变量定义在函数外部,代码最前面的一般情况下都是全局变量。

在 JavaScript 中,全局变量是挂载在 window 对象下的变量,所以在网页中的任何位置你都可以使用并且访问到这个全局变量。下面通过看一段代码来说明一下什么是全局的作用域。

var globalName = 'global';

function getName() { 

  console.log(globalName) // global

  var name = 'inner'

  console.log(name) // inner

} 

getName();

console.log(name); // 

console.log(globalName); //global

function setName(){ 

  vName = 'setName';

}

setName();

console.log(vName); // setName

console.log(window.vName) // setNamevar globalName = 'global';

function getName() { 

  console.log(globalName) // global

  var name = 'inner'

  console.log(name) // inner

} 

getName();

console.log(name); // 

console.log(globalName); //global

function setName(){ 

  vName = 'setName';

}

setName();

console.log(vName); // setName

console.log(window.vName) // setName
  • 从这段代码中我们可以看到,globalName 这个变量无论在什么地方都是可以被访问到的,所以它就是全局变量。而在 getName 函数中作为局部变量的 name 变量是不具备这种能力的。
  • 如果在 JavaScript 中所有没有经过定义,而直接被赋值的变量默认就是一个全局变量,比如上面代码中 setName 函数里面的 vName 变量一样。
  • 我们可以发现全局变量也是拥有全局的作用域,无论你在何处都可以使用它,在浏览器控制台输入 window.vName 的时候,就可以访问到 window 上所有全局变量。
  • 当然全局作用域有相应的缺点,我们定义很多全局变量的时候,会容易引起变量命名的冲突,所以在定义变量的时候应该注意作用域的问题。

2. 函数作用域

在 JavaScript 中,函数中定义的变量叫作函数变量,这个时候只能在函数内部才能访问到它,所以它的作用域也就是函数的内部,称为函数作用域,下面我们来看一段代码。

function getName () {

  var name = 'inner';

  console.log(name); //inner

}

getName();

console.log(name);

上面代码中,name 这个变量是在 getName 函数中进行定义的,所以 name 是一个局部的变量,它的作用域就是在 getName 这个函数里边,也称作函数作用域。

除了这个函数内部,其他地方都是不能访问到它的。同时,当这个函数被执行完之后,这个局部变量也相应会被销毁。所以你会看到在 getName 函数外面的 name 是访问不到的。

下面再来看最后一个块级作用域。

3.块级作用域

ES6 中新增了块级作用域,最直接的表现就是新增的 let 关键词,使用 let 关键词定义的变量只能在块级作用域中被访问,有“暂时性死区”的特点,也就是说这个变量在定义之前是不能被使用的。

听起来好像还不是很能理解块级作用域的意思,那么我们来举个更形象例子,看看到底哪些才是块级作用域呢?其实就是在 JS 编码过程中 if 语句及 for 语句后面 {...} 这里面所包括的,就是块级作用域。

下面结合一段代码来说明。

console.log(a) //a is not defined

if(true){

  let a = '123'console.log(a); // 123

}

console.log(a) //a is not defined

从这段代码可以看出,变量 a 是在 if 语句{...} 中由 let 关键词进行定义的变量,所以它的作用域是 if 语句括号中的那部分,而在外面进行访问 a 变量是会报错的,因为这里不是它的作用域。所以在 if 代码块的前后输出 a 这个变量的结果,控制台会显示 a 并没有定义。