范围是确定变量可用性的重要概念。这个概念是闭包的核心,将变量分为全局和局部。
在本文中,我将尝试简单地解释一下JavaScript的作用域。
1.范围
在深入探讨示波器的细节之前,让我们看一个简单的例子。
假设我们已经定义了一个变量:
const message = 'Hello'
console.log(message) // 'Hello'
我们可以轻松地将其值输出到控制台。这很清楚。
现在,将消息变量的声明放置在if块中:
if (true) {
const message = 'Hello'
}
console.log(message) // ReferenceError: message is not defined
这次,当尝试访问变量时,抛出ReferenceError:消息未定义异常。
为什么会这样?
因为if块已为message变量创建了作用域。并且消息仅在此范围内可用。
因此,变量的可用性受其定义范围的限制。
因此范围是变量的范围。
2.区块范围
JavaScript中的代码块定义了用const和let关键字声明的变量的范围:
if (true) {
// if
const message = 'Hello'
console.log(message) // 'Hello'
}
console.log(message) // ReferenceError
第一个console.log()安全地将message变量的值打印到控制台,因为在定义它的作用域中可以访问此变量。
但是,调用第二个console.log()会引发错误,因为message变量在其外部作用域中不可用:message在当前上下文中不存在。
if,for,while语句中也会创建块作用域。
例如:
for (const color of ['green', 'red', 'blue']) {
// for
const message = 'Hi'
console.log(color) // 'green', 'red', 'blue'
console.log(message) // 'Hi', 'Hi', 'Hi'
}
console.log(color) // ReferenceError
console.log(message) // ReferenceError
颜色和消息变量仅存在于for块内。
while语句也是如此:
while (/* */) {
// while
const message = 'Hi'
console.log(message) // 'Hi'
}
console.log(message) // ReferenceError
在while中定义的消息仅在此循环内可用。
在JavaScript中,您可以创建独立的代码块。它们还定义了自己的范围:
{
const message = 'Hi'
console.log(message) // 'Hi'
}
console.log(message) // ReferenceError
2.1。var不是块作用域
正如我们在前面的示例中看到的,代码块为使用const和let关键字声明的变量创建范围。但是,这不适用于使用var关键字声明的变量。
让我们考虑一个例子:
if (true) {
// if
var count = 0
console.log(count) // 0
}
console.log(count) // 0
如预期的那样,变量计数在if块内可用。但是,它也可以在此块之外使用!
关键是该代码块不会为使用var关键字声明的变量创建范围。但是功能可以做到。
3.功能范围
JavaScript中的函数会为所有变量创建作用域,无论使用什么关键字(var,const或let)声明它们。
例如:
function run() {
// run()
var message = ', , !'
console.log(message)
}
run() // ', , !'
console.log(message) // ReferenceError
run()函数创建一个作用域。message变量在函数内部可用,但不能在外部使用。
同样,该函数为用const和let声明的变量甚至其他函数和函数表达式创建范围:
function run() {
// run()
const two = 2
let one = 1
function run2() {}
var run3 = () => {}
console.log(two)
console.log(one)
console.log(run2)
console.log(run3)
}
run() // 2 1 ƒ run2() {} () => {}
console.log(two) // ReferenceError
console.log(one) // ReferenceError
console.log(run2) // ReferenceError
console.log(run3) // ReferenceError
4.模块可见性
ES6模块还为变量,函数和类创建范围。
circle模块创建一个常数pi(供内部使用):
// circle
const pi = 3.14
console.log(pi) // 3.14
// pi
pi变量在circle模块内部声明,并且不从那里导出。
然后导入circle模块:
import './circle'
console.log(pi) // ReferenceError
变量pi在circle模块之外不可用(直到使用export导出为止)。
模块化范围封装了模块。这意味着私有变量(未导出)用于模块自身的需求,并受到保护,免受外部访问。
因此,可以说范围是代码,功能和模块块的封装机制。
5.范围可以嵌套
范围的一个有趣特征是它们可以相互嵌套。
在下面的示例中,run()函数创建一个范围,在其中,一个if块创建另一个范围:
function run() {
// run()
const message = ', , !'
if (true) {
// if
const friend = ''
console.log(message) // ', , !'
}
console.log(friend) // ReferenceError
}
run()
if块的范围嵌套在run()函数的范围内。
另一个作用域内部的作用域称为内部作用域。在上面的示例中,这是if块的范围。
包含另一个范围的范围称为外部范围。在上面的示例中,这是run()函数的范围。
那么可变可用性呢?要记住的一个简单规则是:
外部作用域中的变量在内部作用域中可用。
因此,消息变量在if块内可用。
6.全球范围
全局范围是最外部的范围。它可用于任何内部或本地范围。在浏览器中,加载脚本标记的src属性中指定的JavaScript文件时会创建全局作用域:
<script src="script.js">
// script.js
//全局范围
let counter = 1
全局范围中声明的变量是全局变量。它们在任何其他区域都可用。
全局范围是一种机制,它允许JavaScript运行时(浏览器,Node.js)将主机(即,环境拥有的)对象作为全局变量公开给应用程序。
例如,窗口和文档是浏览器提供的全局变量(对象)。在Node.js中,此类变量是例如流程对象。
7.词法范围
让我们定义两个函数,其中一个嵌套在另一个函数中:
function outer() {
// outer()
let v = ' outer()!'
function inner() {
// inner()
console.log(v) // ' outer()!'
}
return inner
}
const f = outer()
f()
看一下最后一行:inner()在外部()的范围之外调用。 JavaScript如何知道在inner()函数中打印到控制台的值属于在external()函数中声明的变量v?
答:感谢词法作用域。
JavaScript实现了一种称为词法作用域或静态作用域的机制。词法作用域意味着变量的可访问性由这些变量在嵌套函数范围内的位置静态确定:来自外部函数范围的变量在嵌套函数范围内可用。
词汇范围的正式定义如下:
词汇范围由静态定义的外部范围组成,即 通过使用内部函数中来自那些区域的变量来固定外部区域中的变量。
在上面的示例中,inner()函数的词汇范围由outer()函数的范围组成。
而且,inner()是一个闭包,因为它使用了词法作用域中的变量值。
8.变量隔离
显然,范围隔离了变量。这允许不同的作用域包含具有相同名称的变量。
您可以使用变量count,index,current,value等。在不同区域没有冲突的威胁(名称冲突)。
例如:
function foo() {
// foo()
let count = 1
console.log(count) // 1
}
function bar() {
// bar()
let count = 2
console.log(count) // 2
}
foo()
bar()
结论
范围决定了变量的可用性。当前范围中声明的变量仅在其中可用。
在JavaScript中,作用域是由块,函数和模块创建的。
用const和let关键字声明的变量可以是块,函数或模块化的,而用var关键字声明的变量不是块范围的。
范围可以嵌套。在外部范围中声明的变量在内部范围中可用。
词法范围由静态定义的外部范围组成。任何函数,无论执行位置如何,都可以从其词法范围访问变量(这是闭包的本质)。
我希望这篇文章对您有用。感谢您的关注。