news 2026/10/7 2:13:14

JavaScript 全局对象(globalThis/window/global)完全指南:从作用域规则到 polyfill 实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaScript 全局对象(globalThis/window/global)完全指南:从作用域规则到 polyfill 实战
  • 文档
  • 教程
  • 前端

【免费下载链接】zh.javascript.info

现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。

项目地址:https://gitcode.com/gh_mirrors/zh/zh.javascript.info
点击查看免费下载

全局对象是 JavaScript 运行时提供的“公共舞台”,其中存放着语言内建对象(如Array、Promise)以及环境特有的值(如浏览器中的window.innerHeight)。本篇指南以《现代 JavaScript 教程》中“全局对象”一章为骨架,结合本仓库 1-js/13-modules/01-modules-intro/article.md(模块机制)、1-js/03-code-quality/06-polyfills/article.md(polyfill 与转译器)以及 1-js/06-advanced-functions/04-var/article.md(老旧的var)等章节的源码级证据,帮你彻底理解:全局对象有哪些名字、var与let声明在全局作用域上的天壤之别、如何安全地向全局对象写入共享数据,以及如何借助全局对象编写 polyfill 检测旧环境。

什么是全局对象

全局对象(global object)提供可在任何地方使用的变量和函数。默认情况下,这些全局变量内建于语言或环境中,无论代码写在哪个作用域,都可以直接访问它们。

不同 JavaScript 运行环境对全局对象有不同的命名:

环境全局对象名称
浏览器window
Node.jsglobal
其他环境可能有别的名字

最近,globalThis被作为全局对象的标准名称加入到了 JavaScript 中,所有环境都应该支持该名称,所有主流浏览器都已支持它。

因此在实际编码中有一个实用建议:如果你的脚本只在浏览器中运行,可以放心使用window;但如果脚本可能运行在其他环境(Node.js、Web Worker 等),则最好使用globalThis,以保证代码跨环境的可移植性。

全局对象的属性可以被直接访问

全局对象的所有属性都可以被直接访问,也就是说window上的属性等同于全局作用域中的变量:

alert("Hello"); // 等同于 window.alert("Hello");

反过来,在全局作用域中用var声明的变量,也会自动挂载到全局对象上,从而获得“处处可见”的能力。

var声明的全局变量会成为全局对象的属性

在浏览器中,使用var(而不是let/const!)声明的全局函数和变量,会成为全局对象的属性:

var gVar = 5; alert(window.gVar); // 5(成为了全局对象的属性)

函数声明(特指在主代码流中具有function关键字的语句,而不是函数表达式)也有同样的效果。

但请不要依赖这种行为!它只是出于历史兼容性而保留的旧机制。现代脚本使用 JavaScript 模块(import/export),不会产生这种“污染全局对象”的效果。

如果我们使用let声明,就不会发生这种情况:

let gLet = 5; alert(window.gLet); // undefined(不会成为全局对象的属性)

为什么会这样?从源码角度看,这是var与let在声明语义上的本质区别。本教程 老旧的 "var" 一章详细讲解了var没有块级作用域、变量提升等“远古怪兽”特性——正是这种“函数作用域或全局作用域”的声明规则,使得顶层var声明会与全局对象绑定;而let/const采用块级词法作用域,不会写入全局对象。

如何显式地向全局对象写入共享值

如果一个值非常重要,以至于你想使它在全局范围内可用,可以直接将其作为属性写入全局对象:

// 将当前用户信息全局化,以允许所有脚本访问它 window.currentUser = { name: "John" }; // 代码中的另一个位置 alert(currentUser.name); // John // 或者,如果我们有一个名为 "currentUser" 的局部变量 // 从 window 显式地获取它(这是安全的!) alert(window.currentUser.name); // John

这里蕴含着一个重要的最佳实践:当局部作用域中存在同名变量时,通过window.x显式访问全局对象属性是安全的,可以避免名字遮蔽(shadowing)带来的歧义。

不过,教程同时也给出了严肃的忠告:一般不建议使用全局变量,全局变量应尽可能的少。与使用外部变量或全局变量相比,函数获取“输入”变量并产生特定“输出”的代码设计更加清晰、不易出错且更易于测试。把共享数据显式挂到全局对象上,应仅限于“项目级确实需要全局共享”的少量场景。

模块环境下的全局变量真相

在浏览器中,每个<script type="module">都有独立的顶级作用域,模块之间看不到彼此的顶层变量。本仓库的示例 scopes.view/user.js 中let user = "John";声明了一个模块级变量,另一个脚本试图直接访问它会报错;而正确做法是像 scopes-working.view/user.js 那样用export let user = "John";导出,再由 scopes-working.view/hello.js 通过import {user} from './user.js'导入使用。

也就是说,对于模块,我们应该使用导入/导出交换数据,而不是依赖全局变量。但如果你确实需要创建“窗口级别”的全局变量,可以显式地赋值给window的一个属性,例如window.user = "John"——这样所有脚本(无论是否带有type="module")都能看到它。需要注意的是,模块章节同样强调:创建这种全局变量并不是一个好的方式,请尽量避免。

使用全局对象检测环境并编写 polyfill

我们使用全局对象来测试对现代语言功能的支持。例如,测试环境中是否存在内建的Promise对象(在版本特别旧的浏览器中不存在):

if (!window.Promise) { alert("Your browser is really old!"); }

如果没有(例如我们使用的是旧版浏览器),那么就可以创建 “polyfills”——添加环境不支持但在现代标准中存在的功能:

if (!window.Promise) { window.Promise = ... // 定制实现现代语言功能 }

polyfill 的底层原理:动态语言的可修补性

polyfill 之所以可行,是因为JavaScript 是一种高度动态的语言,脚本可以添加/修改任何函数,甚至包括内建函数。这一点在本教程 Polyfill 和转译器 一章有详尽的展开。

polyfill 的典型写法是“先检测、后修补”。比如Math.trunc(n)是一个“截断”数字小数部分的函数,Math.trunc(1.23)返回1,但一些非常过时的 JavaScript 引擎中并没有这个函数,此时可以这样实现 polyfill:

if (!Math.trunc) { // 如果没有这个函数 // 实现它 Math.trunc = function(number) { // Math.ceil 和 Math.floor 甚至存在于上古年代的 JavaScript 引擎中 return number < 0 ? Math.ceil(number) : Math.floor(number); }; }

同理,现代语法层面的新特性(如空值合并运算符??)无法靠 polyfill 解决,需要借助转译器(Transpiler)处理——例如 Babel 会把height = height ?? 100;重写为height = (height !== undefined && height !== null) ? height : 100;。这就是“新语法用转译器、新内建函数用 polyfill”的分工原则:

  • 转译器:解析现代代码并改写为旧引擎能理解的语法结构;
  • polyfill:直接向全局对象(或内建对象)补充缺失的函数实现。

在实际项目中,两个著名的 polyfill 库包括 core-js(支持大量特性、允许按需引入)等;而 webpack 等现代构建系统提供了在每次代码变更时自动运行转译器的方法,可无缝集成到开发流程中。

总结

  • 全局对象包含应该在任何位置都可见的变量,其中包括 JavaScript 的内建方法(如Array)和环境特有的值(如浏览器中的window.innerHeight—— 窗口高度)。
  • 全局对象有一个通用名称globalThis;但更常见的是使用“老式”的环境特定名称,例如window(浏览器)和global(Node.js)。
  • 仅当值对于项目而言确实是全局的时候,才应将其存储在全局对象中,并且要保持数量最少。
  • 在浏览器中,除非我们使用 模块,否则使用var声明的全局函数和变量会成为全局对象的属性;let/const则不会。
  • 为了使代码面向未来并更易于理解,我们应该使用直接的方式访问全局对象的属性,如window.x。

一句话实践准则:跨环境代码优先使用globalThis;确实需要全局共享的数据用window.x = ...显式写入并尽量少用;而检测旧环境、补齐缺失内建能力(polyfill)时,全局对象就是你最可靠的“侦察与修补”入口。

  • 文档
  • 教程
  • 前端

【免费下载链接】zh.javascript.info

现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScript 相关知识。

项目地址:https://gitcode.com/gh_mirrors/zh/zh.javascript.info
点击查看免费下载
上一篇:揭秘悟空CRM技术架构:TP5.0后端与Vue前端分离的实现原理
下一篇:终极指南:3步快速掌握bkcrack,轻松破解传统ZIP加密文件

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 2:12:55

代理记账许可证编号怎么查?DLJZ 编号含义与查验方法

代理记账许可证编号怎么查&#xff1f;DLJZ 编号含义与查验方法 一分钟看答案 正规代理记账机构的《代理记账许可证书》编号以 DLJZ 开头&#xff08;DL代理&#xff0c;JZ记账&#xff09;&#xff0c;后面是地区行政区划码、核发年份和流水号。查验只要三步&#xff1a; 要编…

作者头像 李华
网站建设 2026/10/7 2:11:16

AI工作流实战:WorkBuddy技能封装与本地化搭建指南

如果你最近在关注 AI 工作流&#xff0c;可能会发现一个现象&#xff1a;Coze、Dify、n8n 这类工具已经把“搭建工作流”讲得很透了&#xff0c;教程遍地都是&#xff0c;但真正落到自己项目里的却不多。原因倒不难理解——很多演示停留在“拖几个节点、点一下运行、截图发朋友…

作者头像 李华
网站建设 2026/10/7 2:11:13

题解:洛谷 P3366 【模板】最小生成树

本文分享的必刷题目是从蓝桥云课、洛谷、AcWing等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。 欢迎大家订阅我的专栏:算法…

作者头像 李华
网站建设 2026/10/7 2:10:06

终端编码代理pi:自主执行代码任务的AI Agent实战解析

pi这个词&#xff0c;最近在开发者圈子里有点热。无论是GitHub Trending还是技术流时间线&#xff0c;都能看到有人聊pi、pi agent、pi coding agent这类话题。简单说&#xff0c;pi就是一个跑在终端里的AI编码代理&#xff0c;你给它一句话或一个任务&#xff0c;它就自己完成…

作者头像 李华
网站建设 2026/10/7 2:08:53

Unity UGUI摇杆控制物体移动:从搭建到手感调优的完整指南

简介&#xff1a;本资源面向Unity初学者与独立开发者&#xff0c;聚焦UGUI摇杆制作与物体移动控制这一常见交互需求。内容围绕Canvas、RectTransform、Image等核心组件展开&#xff0c;讲解摇杆背景与滑块的搭建方式&#xff0c;并通过C#脚本计算输入方向、驱动Rigidbody物体移…

作者头像 李华