聊一聊js的全局作用域和局部作用域

题目

js 复制代码
var a = 10;

function fn1(){
  console.log(a)
}

function fn2() {
  var a = 20;
  fn1();
}

fn2();

结果是10


代码解释

这段代码的输出结果是 10,而不是 20,这是由 JavaScript 的作用域链(Scope Chain)和词法作用域(Lexical Scoping) 决定的。

代码执行流程

  1. 全局作用域

    • var a = 10 声明了一个全局变量 a,值为 10
    • fn1fn2 也被定义在全局作用域。
  2. 调用 fn2()

    • 进入 fn2 的执行上下文,var a = 20 声明了一个 局部变量 a (只属于 fn2 的作用域)。
    • 调用 fn1()
  3. 调用 fn1()

    • fn1 内部访问 a,但 fn1 自身没有定义 a ,于是 沿着作用域链向上查找
    • fn1 是在 全局作用域 中定义的,所以它的作用域链是:
      • fn1 的局部作用域 → 全局作用域。
    • 它不会访问 fn2 的局部变量 a(因为 fn2 的作用域不在 fn1 的作用域链上)。
    • 最终找到的是 全局变量 a(值为 10 ,所以输出 10

关键点:词法作用域(Lexical Scoping)

JavaScript 的作用域是 静态(词法)作用域 ,即 函数的作用域在定义时就已经确定,而不是在执行时

  • fn1 是在全局作用域定义的,所以它只能访问:
    • 自己的局部变量(这里没有)。
    • 全局变量(a = 10)。
  • 不会 访问 fn2 的局部变量 a = 20,因为 fn2 的作用域不是 fn1 的父级作用域。

如果想让 fn1 访问 fn2a

需要改变 fn1 的作用域链,比如:

javascript 复制代码
var a = 10;

function fn2() {
  var a = 20;
  function fn1() {  // fn1 现在定义在 fn2 内部
    console.log(a);  // 此时 a 是 fn2 的局部变量 20
  }
  fn1();
}

fn2();  // 输出 20

此时 fn1 的作用域链是:fn1fn2 → 全局,所以它能访问 fn2a

总结

  • JavaScript 的作用域是静态的(词法作用域),函数的作用域在定义时就已经固定,不会因为调用位置而改变。
  • fn1 定义在全局,所以它只能访问全局变量 a = 10,而不会受到 fn2 的局部变量影响。
  • 如果希望 fn1 访问 fn2 的变量,必须让 fn1fn2 内部定义(形成闭包)。

变通

js 复制代码
var a = 10;

function fn2() {
  var a = 20;
  
  function fn1(){
    console.log(a)
  }
  
  fn1();
}

fn2();

结果是20

每日一句:说话是一件靠自己用点心,就可以不断进步的事。而把话说好,收获最大,当然也是我们自己。

相关推荐
程序员爱钓鱼几秒前
Python编程实战——Python实用工具与库:Matplotlib数据可视化
前端·后端·python
程序员爱钓鱼4 分钟前
Python编程实战 - Python实用工具与库 - requests 与 BeautifulSoup
前端·后端·python
wyzqhhhh5 分钟前
前端跨页面通信
前端
火龙谷14 分钟前
DrissionPage遇到iframe
开发语言·前端·javascript
艾小码31 分钟前
从零到一:这篇JavaScript指南让你成为独立开发者
前端·javascript
顾安r6 小时前
11.8 脚本网页 星际逃生
c语言·前端·javascript·flask
Hello.Reader6 小时前
Data Sink定义、参数与可落地示例
java·前端·网络
im_AMBER6 小时前
React 17
前端·javascript·笔记·学习·react.js·前端框架
谷歌开发者7 小时前
Web 开发指向标 | Chrome 开发者工具学习资源 (六)
前端·chrome·学习