作用域和作用域链
大约 6 分钟
作用域和作用域链
一.作用域
在JavaScript中,作用域(Scope)定义了变量和函数的可访问范围和生命周期。它是一套规则,用于确定在代码的哪些部分可以查找和使用特定的变量或函数。
1. 全局作用域(Global Scope)
在最外层定义的变量或函数,可以在整个程序中访问。
var globalVar = "I'm global";
function globalFunction() {
console.log("I'm also global");
}2. 函数作用域(Function Scope)
在函数内部定义的变量,只能在该函数内部访问。
function myFunction() {
var localVar = "I'm local";
console.log(localVar); // 可以访问
}
console.log(localVar); // 错误:localVar未定义3. 块级作用域(Block Scope)
ES6引入了let和const关键字,它们创建的变量具有块级作用域,所声明的变量在指定块的作用域外无法被访问。
let:
- 用于声明可以重新赋值的变量
- 具有块级作用域
- 不允许在同一作用域内重复声明
const:
- 用于声明常量,即一旦赋值就不能更改的变量
- 也具有块级作用域
- 必须在声明时初始化
- 不允许重新赋值,但如果值是对象或数组,其属性或元素可以修改
块级作用域在以下情况下创建:
- 在函数内部
- 在一个代码块(由一对花括号包裹)内部
if (true) {
let blockVar = "I'm in a block";
const blockConst = "I'm also in a block";
}
console.log(blockVar); // 错误:blockVar未定义
console.log(blockConst); // 错误:blockConst未定义4. 词法作用域(Lexical Scope)
内部函数可以访问外部函数的变量,这种嵌套的作用域链称为词法作用域。(词法作用域由书写代码时函数声明的位置来决定的。)
二.作用域链
1.什么是自由变量?
- 自由变量的特点:
- 它在函数内部被使用,但不是在函数内部定义的。
- 它通常来自于函数的外部作用域(例如,父函数的作用域或全局作用域)。
- 自由变量是闭包形成的重要元素之一。
在JavaScript中,自由变量的访问是通过作用域链实现的。当函数需要访问一个变量时,它首先在自己的作用域中查找。如果没有找到,就会沿着作用域链向外查找,直到找到该变量或到达全局作用域。
这个概念与页面中提到的作用域链密切相关。作用域链允许内部函数访问外部作用域的变量,这正是自由变量的工作原理。
var a = 100;
function fn() {
var b = 200;
console.log(a); // 100 这里 a 就是自由变量
console.log(b); // 200
}
fn();作用域链的形成过程
- **在函数创建时,它的作用域链就已经确定了。**这个作用域链包括:
- 函数自身的变量对象(包含其参数、内部声明的变量等)
- 函数的外部环境的变量对象
- 全局环境的变量对象
- 当函数执行时,会创建一个执行环境(execution context)。这个执行环境的作用域链是基于函数的作用域链创建的。
作用域链的作用
- 变量查找:当代码需要访问一个变量时,它会首先在当前作用域中查找。如果没有找到,就会沿着作用域链向外层作用域查找,直到全局作用域。
- 闭包实现:作用域链使得内部函数可以访问外部函数的变量,这是闭包实现的基础。
- 命名空间:作用域链有助于避免命名冲突,因为内部作用域可以遮蔽外部作用域的同名变量。
示例
var global = "global";
function outer() {
var outer = "outer";
function inner() {
var inner = "inner";
console.log(inner); // 在当前作用域找到
console.log(outer); // 在外层作用域找到
console.log(global); // 在全局作用域找到
}
inner();
}
outer();在这个例子中,inner函数的作用域链包括:inner的变量对象 -> outer的变量对象 -> 全局变量对象。这就是为什么inner函数可以访问所有这些变量的原因。
总结:
1. 作用域(Scope)
- 定义了变量和函数的可访问范围和生命周期
- 包括全局作用域、函数作用域和块级作用域
- ES6引入的let和const关键字创建块级作用域
2. 词法作用域(Lexical Scope)
- 内部函数可以访问外部函数的变量
- 由函数定义的位置决定,而非调用位置
3. 自由变量
- 在函数内部使用但不在函数内定义的变量
- 通过作用域链访问
4. 作用域链
- 在函数创建时确定,包括函数自身、外部环境和全局环境的变量对象
- 用于变量查找、闭包实现和避免命名冲突
这些概念共同构成了JavaScript中变量访问和函数执行的基础机制,对理解代码的运行和编写高效的JavaScript程序至关重要。
