聊一聊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

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

相关推荐
大飞记Python1 分钟前
部门管理|“编辑部门”功能实现(Django5零基础Web平台)
前端·数据库·python·django
tsumikistep1 小时前
【前端】前端运行环境的结构
前端
你的人类朋友1 小时前
【Node】认识multer库
前端·javascript·后端
Aitter1 小时前
PDF和Word文件转换为Markdown的技术实现
前端·ai编程
mapbar_front2 小时前
面试问题—上家公司的离职原因
前端·面试
昔人'2 小时前
css使用 :where() 来简化大型 CSS 选择器列表
前端·css
昔人'2 小时前
css `dorp-shadow`
前端·css
流***陌3 小时前
扭蛋机 Roll 福利房小程序前端功能设计:融合趣味互动与福利适配
前端·小程序
烛阴3 小时前
用 Python 揭秘 IP 地址背后的地理位置和信息
前端·python
前端开发爱好者3 小时前
尤雨溪官宣:"新玩具" 比 Prettier 快 45 倍!
前端·javascript·vue.js