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 变量声明
- 函数声明优先级高于变量声明
- 函数声明不会被变量声明覆盖
- 变量赋值会覆盖函数声明
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)特性
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:函数参数与作用域
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 与形参绑定
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);
关键结论
- 声明优先级:函数声明 > 参数 > 变量声明
- 提升规则:
var
:提升声明(值为undefined
)function
:提升完整定义
- 作用域边界:
if
块中的function
声明影响外部作用域- IIFE 创建独立作用域
- 现代语法:
let/const
无提升,有 TDZ 保护- 参数默认值创建独立作用域链