作用域决定了变量
、函数
和对象
的可访问范围,是JavaScript最基础的核心机制
一、作用域类型
全局作用域:脚本最外层声明的变量
const globalVar = '全局变量' ;
function test ( ) {
console. log ( globalVar) ;
}
函数作用域:通过var或函数声明创建
function funcScope ( ) {
var funcVar = '函数内部变量' ;
console. log ( funcVar) ;
}
console. log ( funcVar) ;
块级作用域(ES6+)
:通过let/const
创建
if ( true ) {
let blockVar = '块级变量' ;
const PI = 3.14 ;
}
if ( true ) { let blockVar = '块级变量' ; const PI = 3.14 ; }
二、作用域链:变量的寻址导航系统
访问变量时,JavaScript会沿着作用域链逐级向上查找
1. 链式结构形成原理
let global = 'G' ;
function outer ( ) {
let outerVar = 'O' ;
function inner ( ) {
let innerVar = 'I' ;
console. log ( innerVar) ;
console. log ( outerVar) ;
console. log ( global) ;
}
inner ( ) ;
}
outer ( ) ;
inner作用域 → outer作用域 → 全局作用域 → null
2. 关键特性
静态词法作用域:链的链接关系在代码编写阶段确定
单向访问:内部作用域可访问外部,反之不行
遮蔽效应:同名变量会覆盖外层定义
let x = 10 ;
function shadowDemo ( ) {
let x = 20 ;
console. log ( x) ;
}
三、执行上下文与作用域链的关系
每次函数调用都会创建新的执行上下文,其包含三个核心部分:
1:变量环境(Variable Environment)
2:词法环境(Lexical Environment)
3:this绑定
ExecutionContext = {
VariableEnvironment: { } ,
LexicalEnvironment: {
outer: < 父级词法环境引用> ,
} ,
ThisBinding: < this 值>
}
四、闭包:作用域链的经典应用
1: 闭包的本质是函数与其词法环境的引用捆绑。
function createCounter ( ) {
let count = 0 ;
return {
increment : ( ) => { count++ ; } ,
getValue : ( ) => count
} ;
}
const counter = createCounter ( ) ;
const counter = createCounter ( ) ;
console. log ( counter. getValue ( ) ) ;
2.:闭包的应用场景
模块化开发(私有变量封装)
防抖/节流函数
缓存计算结果
循环中正确处理异步回调
五、常见问题
1. 循环变量陷阱(经典面试题)
for ( var i = 0 ; i < 3 ; i++ ) {
setTimeout ( ( ) => {
console. log ( i) ;
} , 100 ) ;
}
for ( let i = 0 ; i < 3 ; i++ ) {
setTimeout ( ( ) => {
console. log ( i) ;
} , 100 )
}
2. 变量提升的坑
console. log ( a) ;
var a = 10 ;
console. log ( b) ;
let b = 20 ;
3. 严格模式的影响
'use strict' ;
function strictDemo ( ) {
undeclaredVar = 10 ;
}
七、思考
尽可能最小化全局变量:使用IIFE封装代码
优先使用const/let:避免变量提升问题
合理使用闭包:注意内存泄漏风险
模块化开发:使用ES6 Module管理作用域
命名空间模式:减少全局污染