最近接手之前同事开发的项目,频繁见到这样的写法:
export const getWechatVersion = () \=>
global.navigator.userAgent.match(/MicroMessenger\\/(\[\\d\\.\]+)/i)\[1\];
export const getAlipayVersion = () \=>
global.navigator.userAgent.match(/AlipayClient\\/(\[\\d\\.\]+)/i)\[1\];
const { wx } = global;
所以,感到很困惑,navigator 在window下存在,在node下undefined,项目打包了在浏览器中又可以获取到navigator。
在webpack构建的react,vue 项目中使用global 与 globals 库到底有什么用?
这就是 JS 历史遗留问题,最近才被一个提案给修正了。
浏览器环境中如果想要访问全局作用域,要使用
window
,而 nodejs 环境中虽然没有 DOM 概念,但是类似的 setTimeout/clearTimeout 还是有的,他们也同样存在于全局作用域。 nodejs 使用了global
标识符来访问全局作用域。这样就导致了一个问题,如果一个库的作者想要暴露方法到全局空间,就需要探测当前的环境是浏览器还是 nodejs,浏览器里还分代码是否在 worker 进程里, 要加 if(typeof window === 'undefined') else if(typeof self === 'undefined') 之类的判断,最不济就用顶层的 this 当全局作用域。于是有人把这个检测过程提炼出来,做成了一个 npm 包,你只要用这个包来访问全局空间,不用关心实际运行环境了。就是题中的 global 包。
Webpack 于是说,哎你们用 webpack 打包代码的,不用费心啦,只要根据你们的目标平台,用插件就可以无痛替换
global
为window
啊self
啊, 源码里你就放心用global
啦。TC39 说,怎么这么乱,不行,这得标准化才行。但是问题是很多代码把检测到
global
作为是非浏览器环境的信号,检测到就各种 module exports 用起来。为了兼容性,标准把这东西叫globalThis
。至于你图中另一个 npm 包 globals,那是一个定义各种 JS 环境全局空间下都有什么的库,包括一些由框架预处理好的 nodejs 环境,比如 mocha jest 测试环境。介绍里也说了,它是从 eslint 中提取出来的。这个库是给开发工具准备的,和上面的没有关系。