Appearance
JavaScript 变量提升与函数提升
导航目录
变量提升机制
核心概念
- 变量提升:在 JavaScript 执行代码前,引擎会对
var和function声明进行提前处理,将它们移到作用域的顶部 - var 声明:只提升声明部分,初始值为
undefined - function 声明:同时提升声明和定义,包括整个函数体
var 变量声明
javascript
console.log(a); // undefined(变量已声明但未赋值)
var a = 10;function 函数声明
javascript
console.log(a); // [Function: a](函数已完全定义)
function a() {}声明优先级规则
函数声明 vs 变量声明
| 操作 | 结果 | 说明 |
|---|---|---|
| 函数声明 vs 变量声明 | 函数声明优先 | 函数声明不会被变量声明覆盖 |
| 函数声明 vs 变量赋值 | 变量赋值优先 | 变量赋值会覆盖函数声明 |
javascript
// 函数声明优先级更高
console.log(a); // [Function: a]
var a;
function a() {}
// 变量赋值覆盖函数声明
var a = 10;
console.log(a); // 10
function a() {}if 代码块中的特殊行为
关键特性
- 提前声明:if 代码块中的函数会被提升到当前作用域顶部
- 作用域影响:块内的函数声明会影响外部作用域
- 禁止重复声明:禁止在同一作用域内同时使用
var和function声明同名变量
验证示例
1. 提前声明特性
javascript
console.log(a); // undefined(表明已声明但未定义)
if (true) {
function a() {}
}2. 修改不影响全局
javascript
console.log(a); // undefined
var a;
if (true) {
console.log(a); // [Function: a]
a = 10; // 只影响块内
function a() {} // 此处分界:外部a开始关联内部a
a = 20; // 只影响块内
console.log(a); // 20
}
console.log(a); // 10(块内赋值通过function声明影响外部)3. 禁止重复声明
javascript
// 报错:Identifier 'a' has already been declared
if (true) {
function a() {}
var a;
}立即执行函数(IIFE)特性
- IIFE 特性:创建独立作用域,内部变量不会影响外部
- 函数名保护:IIFE 内部无法修改自身的函数名
- 严格模式:严格模式下尝试修改函数名会报错
javascript
var a = 10;
(function a() {
a = 20; // 严格模式下报错,非严格模式赋值无效
console.log(a); // [Function: a]
})();
console.log(a); // 10(IIFE 不影响外部)let/const 声明
核心特性
- 无变量提升:提前访问会报错
- 暂时性死区(TDZ):在声明前的区域访问变量会抛出错误
- 块级作用域:只在声明的块级作用域内有效
javascript
console.log(a); // ReferenceError: Cannot access 'a'
let a = 10;综合案例解析
案例 1:函数覆盖与变量赋值
- 函数声明覆盖:多个同名函数声明,最后一个生效
- 变量赋值覆盖:变量赋值会覆盖函数声明
javascript
fn(); // 5(最后定义的函数生效)
function fn() {
console.log(1);
}
function fn() {
console.log(2);
}
function fn() {
console.log(4);
}
function fn() {
console.log(5);
} // 覆盖之前的声明
var fn = function () {
console.log(3);
}; // 此处覆盖函数定义
fn(); // 3(变量赋值后生效)案例 2:函数参数与作用域
- 形参作用域:函数参数相当于局部变量
- 全局变量访问:函数内部可以访问和修改全局变量
- 无返回值:函数默认返回 undefined
javascript
console.log(a, b, c); // undefined undefined undefined
var a = 12,
b = 13,
c = 14;
function fn(a) {
// 形参 a 相当于局部变量 var a = 10
console.log(a, b, c); // 10 13 14
a = 100; // 修改局部a
c = 200; // 修改全局c
console.log(a, b, c); // 100 13 200
}
b = fn(10); // b 接收 undefined(函数无返回值)
console.log(a, b, c); // 12 undefined 200案例 3:形参与函数声明优先级
- 函数声明优先:函数声明优先级高于函数参数
javascript
function fn(a) {
console.log(a); // [Function: a](函数声明优先级高于形参)
var a = 2;
function a() {}
}
fn(1);案例 4:参数默认值与作用域
- 参数默认值作用域:参数默认值创建独立的作用域链
- 局部变量遮蔽:函数内部的变量会遮蔽外部变量
javascript
var x = 100;
function func(
x,
y = function () {
x = 10;
}
) {
x = 3; // 修改局部x
y(); // 修改局部x=10(y中的x指向第一个参数x)
console.log(x); // 10
}
func();
console.log(x); // 100(全局x不变)案例 5:arguments 与形参绑定
- 形参与 arguments 绑定:当参数被传入时,形参与 arguments 数组元素相互绑定
- 未传入参数:未传入的参数与 arguments 数组元素不绑定
javascript
// 情况1:传入三个参数
function func(a, b, c) {
console.log(c); // 3
arguments[2] = 100; // 修改第三个参数
console.log(c); // 100(c与arguments[2]绑定)
}
func(1, 2, 3);
// 情况2:传入两个参数
function func(a, b, c) {
console.log(c); // undefined(未传入)
arguments[2] = 100; // 添加第三个参数,但不影响c
console.log(c); // undefined(c与arguments[2]不绑定)
}
func(1, 2);关键结论
1. 声明优先级
- 函数声明 > 参数 > 变量声明
2. 提升规则
- var:提升声明(值为
undefined) - function:提升完整定义
3. 作用域边界
- if 块:
function声明影响外部作用域 - IIFE:创建独立作用域
4. 现代语法特性
- let/const:无提升,有 TDZ 保护
- 参数默认值:创建独立作用域链