Skip to content

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 代码块中的特殊行为

关键特性

  1. if 代码块中的函数会提前声明(提升到当前作用域顶部)
  2. 块内修改函数不会影响全局
  3. 禁止同时使用 varfunction 声明同名变量

验证示例

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);

关键结论

  1. 声明优先级:函数声明 > 参数 > 变量声明
  2. 提升规则
    • var:提升声明(值为 undefined
    • function:提升完整定义
  3. 作用域边界
    • if 块中的 function 声明影响外部作用域
    • IIFE 创建独立作用域
  4. 现代语法
    • let/const 无提升,有 TDZ 保护
    • 参数默认值创建独立作用域链