前言
本篇文章主要讲解 JavaScript 中的作用域
作用域(Scope)的概念
很多编程语言都具有作用域的概念,它是计算机程序设计中的一个核心概念,定义了变量(或函数)的可访问范围
在书籍《你不知道的 Javascript》上卷中有这样一句话:作用域是根据名称查找变量的一套规则
所以通俗来讲,作用域在 JavaScript 里可以理解为:作用域是一套规则,可以决定一个变量或函数的有效访问范围
JavaScript 有哪些作用域
不同的编程语言可能有不同的作用域及规则,除去特殊的 eval 作用域,在 JavaScript 中主要有三种作用域:
- 全局作用域
- 函数作用域
- 块级作用域
全局作用域
全局作用域很好理解,在程序执行时就会被创建,特点是程序的任何地方都可以访问到,如果是浏览器环境,则挂载在 window
对象上
js
var a = 'fifteen'
console.log(window.a); // fifteen
函数作用域
函数作用域是指函数内部的区域,特点是:在程序外部无法访问到函数内部的变量
js
function foo() {
var b = "fifteen"
console.log(b);
}
foo() // fifteen
比如我们定义一个 foo
函数,在函数内部定义一个变量 b
此时在 window
对象上只会挂载一个 foo
函数,而不存在变量 b
,在外部访问会报错:Uncaught ReferenceError: b is not defined
块级作用域
块级作用域,使用 {}
包裹的代码,并且使用 let
、const
等关键字声明的变量,会形成块级作用域
也就是说,像常用的 if
、for
、while
、try
、catch
等,都可以形成块级作用域
一个最小化的例子是,在 if
内定义的变量 a
,无法在外部访问
js
if(true){
const a = "fifteen"
}
console.log(a); // Uncaught ReferenceError: a is not defined
而在此之前,通过 var
定义的变量,由于存在变量提升的问题,会污染外部变量
js
if(true){
var b = "fifteen"
}
console.log(b); // fifteen
《Javascript 高级程序设计》第四版和《你不知道的 Javascript》上卷在相关内容中,都举了一个 for
循环的例子
js
for(var i = 0; i < 3; i++){
console.log(i);
}
console.log(i); // 3
在这段循环中,我们用 var
定义了一个 i
变量,定义这个变量的初衷是让它在循环内部控制循环次数,但现在情况不是想象中的这样,i
现在污染了外部环境,是绑定在 window
对象上的全局变量
使用 ES6 推出的 let
定义,情况就不一样了
js
for(let i = 0; i < 3; i++){
console.log(i);
}
现在,i
只能在 for
循环内部使用,外部访问会报错:Uncaught ReferenceError: i is not defined
IIFE 立即执行函数表达式
这一节我想聊聊 IIFE,主要搞懂以下三个问题:
- IIFE 是什么?概念
- 如何定义一个 IIFE?
- IIFE 解决了什么问题,起什么作用
首先,IIFE 是一个缩写,它的全称英文是 Immediately Invoked Function Expression
,翻译过来就是:立即调用的函数表达式
IIFE 的行为,可以理解为一个函数在定义后就会立即执行,表现形式通常用 ()
包裹的匿名函数,尾部再接一个 ()
,触发函数的执行
比如下面这段代码:
js
(function (){
/** code */
})()
这样的操作带来了一些好处,借用 MDN 中介绍 IIFE 的内容:通过创建新的作用域来避免污染全局命名空间
也就是说,IIFE 可以解决变量(函数)污染的问题,形成一个独立的作用域,不会在 window
对象中挂载
它与块级作用域的作用很相似,在 ES6 之前,IIFE 常被用来生成独立的作用域
MDN - IIFE 中列出了 IIFE 的三点作用:
- 通过创建新的作用域来避免污染全局命名空间。
- 创建新的异步上下文以在非异步上下文中使用 await。
- 使用复杂的逻辑计算值,例如将多个语句用作单个表达式。
总结
我们上面讲了三种作用域,分别是:全局作用域、函数作用域、块级作用域,可能你写了很多年的JS,但你没有注意到这些概念,深入学习 Javascript 时,这都是不必可少的基础知识
最后的话,聊了一下 IIFE ,它可以解决变量污染的问题,形成一个独立的作用域,在 ES6 块作用域之前比较常用
参考资料
- 编程语言中的作用域
- 《你不知道的 Javascript》上卷
- 《Javascript 高级程序设计》第四版
- MDN - 立即调用函数表达式
参透JavaScript系列
本文已收录至《参透 JavaScript 系列》,全文地址:我的 GitHub 博客 | 掘金专栏
交流讨论
对文章内容有任何疑问、建议,或发现有错误,欢迎交流和指正