boxmoe_header_banner_img

Hello! 欢迎来到盒子萌!

加载中

文章导读

作用域、变量提升、函数提升


avatar
Jack 2024年 1月 8日 354

💡 作用域(Scope)

一、作用域的概念与分类

🔹 什么是作用域?

  • 定义:作用域是变量或函数的作用范围,在函数定义时就已确定
  • 目的:提高程序可靠性,避免命名冲突。

🔹 JS 中的作用域分类(ES5):

  1. 全局作用域
    • 作用范围:整个 script 标签或独立 JS 文件。
  2. 函数作用域(局部作用域)
    • 作用范围:函数内部。

二、全局作用域与 window 对象

  • 页面打开时创建,关闭时销毁。
  • 全局变量/函数 会挂载到 window 对象上:
const a = 100;
console.log(window.a); // 100
  • 全局函数也是 window 的方法。

三、作用域的访问关系

✅ 规则:内层可以访问外层,反之不行。

const a = 'aaa';
function foo() {
  const b = 'bbb';
  console.log(a); // ✅ 可以访问外部变量
}
foo();
console.log(b); // ❌ 报错:b is not defined

四、变量的作用域分类

🔸 全局变量

  • 在全局作用域中定义,整个代码中都能访问。

🔸 局部变量

  • 定义在函数内部,仅限函数内部访问。
  • 函数参数也是局部变量。

🔸 执行效率

  • 全局变量:占内存,直到页面关闭才释放。
  • 局部变量:函数执行完即销毁,节省内存。

五、变量声明的特殊情况

  1. 未声明直接赋值的变量是全局变量
function fn() {
  a = 1; // 没有 var/let/const,a 成为全局变量
}
fn();
console.log(a); // ✅ 1

⚠️ 不推荐这样使用!

  1. 局部变量与全局变量同名时,优先使用局部变量

六、作用域的就近原则

  • 查找变量时:先当前作用域 → 上层 → 全局,直到找到或报错。
var a = 1;
function fn() {
  var a = 2;
  console.log(a); // ✅ 2,使用局部变量
}
fn();
console.log(a); // ✅ 1
  • 要访问全局变量可使用 window.a

七、预处理(声明提前)

📌 什么是预处理?

  • JS 在执行前会“预处理”变量和函数声明。
  • 行为:将变量/函数声明提前到作用域顶部(变量只声明不赋值)。

变量声明提前(变量提升)

console.log(a); // undefined
var a = 123;
  • 声明提前了,但赋值没有提前。
console.log(a);
a = 123; // ❌ 报错:a is not defined

函数声明提前(函数提升)

fn1(); // ✅ 可以先调用

function fn1() {
  console.log('函数 fn1');
}
  • 函数表达式不会提升:
fun2(); // ❌ 报错
const fun2 = function() {
  console.log('我是 fun2');
};

函数提升优先于变量提升(经典面试题)

fun(); // B

var fun = function () {
  console.log('A');
};

function fun() {
  console.log('B');
}

fun(); // A

解释(伪代码理解):

function fun() { console.log('B'); }
var fun;
fun(); // B
fun = function() { console.log('A'); };
fun(); // A

八、函数作用域中的预处理

  • 函数中 var 声明的变量也会提前。
  • 函数中没有 var 声明的变量则为全局变量。
var a = 1;

function foo() {
  console.log(a);
  a = 2; // 相当于 window.a
}
foo(); // ✅ 1
console.log(a); // ✅ 2

🔹 补充:函数参数相当于在内部声明了变量

function fun(e) {
  console.log(e);
}
fun();     // undefined
fun(123);  // 123

九、ES5 中没有块级作用域 ❗

if (true) {
  var num = 123;
  console.log(num); // 123
}
console.log(num); // ✅ 123(依然可以访问)

不像 Java 等语言中 if/for 等语句块内的变量会被限制作用域。

🔟 作用域链

  • 函数嵌套 = 多层作用域嵌套
  • 变量查找采用就近原则
  • 从内向外链式查找,形成作用域链
var num = 10;

function fn() {
  var num = 20;
  function fun() {
    console.log(num); // ✅ 20,查到外层变量
  }
  fun();
}
fn();

📚 总结建议

  • 开发中应尽量 先声明变量再使用,避免变量提升带来的混淆。
  • 多层函数嵌套时,注意变量名重复问题。
  • ES6 之后可以使用 letconst 创建块级作用域,避免 ES5 的作用域陷阱。


评论(0)

查看评论列表

暂无评论


发表评论

表情 颜文字
插入代码