JavaScript作用域

JavaScript作用域
今晚不熬夜作用域是什么?
作用域是当前的执行上下文,值和表达式在其中可见或可被访问。如果一个变量或表达式不在当前的作用域中,那么它是不可用的。作用域也可以堆叠成层次结构,子作用域可以访问父作用域,反过来则不行。
作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少命名冲突。
JS作用域分类
JavaScript
的作用域分为四种:全局作用域、函数作用域、块级作用域、模块作用域。
除了全局作用域以外的作用域,从意义上都可以叫局部作用域。在全局定义的变量叫全局变量,在局部作用域定义的变量可以叫局部变量。
全局作用域
简单来说,直接编写在 script
标签之中和单独 JS
文件中的代码,都是全局作用域。
全局作用域在页面打开时创建,页面关闭时销毁。
1 | var me = "今晚不熬夜!"; |
在全局作用域下声明的变量叫做全局变量,全局变量在全局(代码的任何位置)下都可以使用,但是全局作用域中无法访问到局部作用域中的变量。
函数作用域
在函数内部就是函数作用域。调用函数时创建函数作用域,函数执行完毕之后,函数作用域销毁,调用一次函数就会创建一个新的函数作用域,它们之间是相互独立的。
1 | function fun(){ |
(注意)如果在函数内部,没有使用var、let、const关键字声明直接赋值的变量也属于全局变量。(不建议使用)
块级作用域
用一对花括号(一个代码块)创建出来的作用域,注意只有用 let 或 const 声明的变量才属于块级作用域。
1 | { |
在块级作用域中,没有使用let、const定义的变量、函数都将成为全局变量。
模块作用域
模块模式中运行代码的作用域。在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,外部文件是访问不到的,也无法访问外部。这种模块级别的访问限制,叫做模块作用域。
m.js
1 | var a = "我在模块里"; |
app.js
1 | import fun from "./m" |
上面有一个m.js模块,里面定义了一个变量a
和暴露了一个函数,然后app.js
导入该模块,由于在模块作用域中m.js
模块只暴露了函数,所以a
变量在app.js
中无法访问。如果看不明白,那你应该看看JS模块化
作用域链
作用域链,简单来说就是,当局部作用域访问变量时,首先看当前作用域下又没有这个变量,如果有就用该变量,没有就访问外层作用域,直到全局作用域为止。(就近原则)
1 | let b = "我是全局变量"; |
静态作用域
静态作用域指的是一段代码,在它执行之前就已经确定了它的作用域,简单来说就是在执行之前就确定了它可以应用哪些地方的作用域。(JavaScript就是静态作用域,也称词法作用域)
1 | let a = "我是全局变量!"; |
大多数现在程序设计语言都是采用静态作用域规则,比如:C、C++、Python、Java、JavaScript、Lua
动态作用域
虽然JavaScript用的是静态作用域,但我觉得还是有必要讲讲什么是动态作用域。
动态作用域下函数的作用域在函数调用的时候才决定的。看看下面bash代码,注意是bash bash
1 | # scope.bash |