前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >用 globalThis 访问全局对象[每日前端夜话0xF6]

用 globalThis 访问全局对象[每日前端夜话0xF6]

作者头像
疯狂的技术宅
发布于 2019-12-11 02:59:17
发布于 2019-12-11 02:59:17
1.3K00
代码可运行
举报
文章被收录于专栏:京程一灯京程一灯
运行总次数:0
代码可运行

正文共:2155 字

预计阅读时间:6 分钟

翻译:疯狂的技术宅 作者:Faraz Kelhini 来源:logrocket

JavaScript 语言越来越被广泛地用于各种环境中。除了 Web 浏览器(这是 JavaScript 的最常见的宿主环境类型)之外,你还可以在服务器,智能手机甚至机器人硬件中运行 JavaScript 程序。

每个环境都有其自己的对象模型,并提供了不同的语法来访问全局对象。例如,在Web浏览器中,可以通过 windowselfframes 访问全局对象。但是在 Node.js 中,这些属性不存在,而你必须使用 global。在 Web Worker 中,只有 self 可用。

这些引用全局对象的不同方式使编写能够在多个环境中工作的可移植 JavaScript 代码变得非常困难。幸运的是,有一个正在开发中的提案【https://github.com/tc39/proposal-global】打算通过引入一个名为 globalThis 的标准属性来解决这个问题,该属性将在所有环境中可用。

在本文中,我们将首先研究流行的 JavaScript 环境中的全局对象,然后看看 globalThis 是如何提供一种统一的机制来访问它。

`window`

window 属性用于在浏览器环境中引用当前文档的全局对象。在代码的顶层,使用 var 关键字声明的变量将成为 window 的属性,并且可能够在代码中的任何位置访问:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var a = [10, 20];

console.log(window.a);          // → [10, 20]
console.log(a === window.a);    // → true

通常在使用 window 的属性时,由于隐含引用的缘故不必直接引用 window。但是当有一个与全局变量同名的局部变量时,使用 window 是唯一的选择:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var a = 10;

(function() {
  var a = 20;   
  console.log(a);           // → 20
  console.log(window.a);    // → 10
})();

如你所见,无论代码在什么作用域内运行,window 对于引用全局对象都非常有用。注意,`window实际上引用了 window.window。因此,window.window === window

除了标准的 JavaScript 属性和方法之外,window 对象还包含其他一些属性和方法,这些属性和方法使我们能够控制 Web 浏览器窗口以及文档本身。

`self`

Web Workers API没有 window 对象,因为它没有浏览上下文。相反,它提供了 WorkerGlobalScope 接口,其中包含通常由 WorkerGlobalScope 承载的数据。

为了访问 Web Workers 中的全局对象,我们需要使用 self,它是 Window 对象的 window 属性的同义词。与 window 类似,self 是对全局对象的引用,可用于显式引用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// a web worker
console.log(self);    // => DedicatedWorkerGlobalScope {...}

var a = 10;

console.log(self.a);          // → 10
console.log(a === self.a);    // → true

在浏览器环境中,此代码将记录 Window 而不是 DedicatedWorkerGlobalScope。由于 self 的值会根据使用环境的不同而变化,所以有时最好使用 Windowself 在 web worker 上下文中引用 WorkerGlobalScope.self,而在浏览器上下文中引用 window.self

重要的是不要将 self 属性与声明局部变量(用于维护对上下文的引用)的常见 JavaScript 模式混淆。例如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const obj = {
  myProperty: 10,
  myMethod: function(){
    console.log(this === obj);    // => true

    // store the value of this in a variable for use in nested functions
    const self = this;

    const helperFunction = (function() {
      console.log(self === obj);  // => true (self refers to the outer this value)
      console.log(this === obj);  // => false (this refers to the global object. In strict mode, it has a value of undefined)
    })();
  }
};

// invoke myMethod on the object obj.
obj.myMethod();

`frames`

另一种在浏览器环境中访问全局对象的方法是使用 frames 属性,该属性的作用类似于 selfwindow

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// browser environment
console.log(frames);    // => Window {...}

这个只读属性通常用于获取当前窗口的子帧列表。例如你可以用 window.frames [0]frames [0] 访问第一帧。

`global`

在 Node.js 中,你可以使用 global 关键字访问全局对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// node environment
console.log(global);    // => Object [global] {...}

windowselfframes 在 Node 环境中不起作用。请记住,Node.js 中的顶级作用域不是全局作用域。在浏览器中,var abc = 123 将创建一个全局变量。但是在 Node.js 中变量是模块本身的局部变量。

`this`

在浏览器中,可以在程序的顶层使用 this 关键字来引用全局对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.foo = 123;
console.log(this.foo === window.foo);    // => true

this 在非严格模式下在函数或箭头函数内也引用全局对象。但是在严格模式下运行的函数就不是这种情况了,其中 this 的值为 undefined

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(function() {
  console.log(this);    // => Window {...}
})();

(() => {
  console.log(this);    // => Window {...}
})();

(function() {
  "use strict";
  console.log(this);    // => undefined
})();

在 Node 模块中,顶层的 this 不引用全局对象。相反,它与 module.exports 具有相同的值。在函数内部(Node 环境),this 的值取决于函数的调用方式。在 JavaScript 模块中,顶层的 thisundefined

介绍 `globalThis`

globalThis 旨在通过定义标准的全局属性来整合越来越分散的访问全局对象的方式。globalThis 提案目前处于第 4 阶段,这意味着它已准备好纳入 ES2020 标准。所有流行的浏览器,包括 Chrome 71 +,Firefox 65+和Safari 12.1+,都已支持该功能。你也可以在 Node.js 12+ 中使用它。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// browser environment
console.log(globalThis);    // => Window {...}

// node.js environment
console.log(globalThis);    // => Object [global] {...}

// web worker environment
console.log(globalThis);    // => DedicatedWorkerGlobalScope {...}

通过使用 globalThis,你的代码能够在窗口和非窗口上下文中工作,而无需编写其他检查或测试代码。在大多数环境中, globalThis 直接引用该环境的全局对象。但是在浏览器中,内部需要使用代理来考虑 iframe 和跨窗口安全性。实际上,它并不会改变你编写代码的方式。

通常,当你不确定要在哪种环境中使用代码时,或者当你想使代码在不同环境中可执行时,可以用 globalThis 属性。不过你必须用 polyfill 在不支持该功能的旧版浏览器上实现该功能。

另一方面,如果需要你确定要在什么环境中使用代码,请使用前面列举引用环境全局对象的现有方法之一,避免为 globalThis 添加 polyfill 的麻烦。

创建一个 `globalThis` polyfill

在引入 globalThis 之前,一种常用的跨环境访问全局对象的方法是使用以下模式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function getGlobalObject() {
  return Function('return this')();
}

if (typeof getGlobalObject().Promise.allSettled !== 'function') {
  // the Promise.allSettled() method is not available in this environment
}

这段代码的问题在于,在强制执行内容安全策略(CSP)【https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP】的网站中不能用 Function 构造函数和 eval。由于CSP的缘故,Chrome 的扩展程序系统也不允许此类代码运行。

引用全局对象的另一种模式如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function getGlobalObject() {
  if (typeof globalThis !== 'undefined') { return globalThis; }
  if (typeof self !== 'undefined') { return self; }
  if (typeof window !== 'undefined') { return window; }
  if (typeof global !== 'undefined') { return global; }
  throw new Error('cannot find the global object');
};

if (typeof getGlobalObject().Promise.allSettled !== 'function') {
  // the Promise.allSettled() method is not available in this environment
}

这种模式通常在 web 上使用。但也有几个缺陷【https://mathiasbynens.be/notes/globalthis#naive-polyfill】,使其在某些情况下不可靠。幸运的是 Chrome DevTools 团队的Mathias Bynens 提出了一种创意模式【https://mathiasbynens.be/notes/globalthis#robust-polyfill】,它没有这些缺点:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(function() {
  if (typeof globalThis === 'object') return;
  Object.defineProperty(Object.prototype, '__magic__', {
    get: function() {
      return this;
    },
    configurable: true // This makes it possible to `delete` the getter later.
  });
  __magic__.globalThis = __magic__; // lolwat
  delete Object.prototype.__magic__;
}());

// Your code can use `globalThis` now.
console.log(globalThis);

与其他方法相比,polyfill 是更可靠的解决方案,但仍然不够完美。正如 Mathias 提到的那样,修改ObjectObject.definePropertyObject.prototype.__defineGetter__ 可能会破坏 polyfill。

总结

能够用在多种环境中的可移植 JavaScript 代码很难编写。每个主机环境都有一个略有不同的对象模型。因此,要访问全局对象,你需要在不同的 JavaScript 环境中使用不同的语法。

通过引入 globalThis 属性,访问全局对象将变得更加简单,并且不再需要去检测代码所运行的环境。

乍一看 globalThis 似乎很容易实现。但是实际上,正确地进行操作是非常复杂的。现有的解决方法都不完美,如果不小心就可能会引入错误。

ECMAScript 正在迅速发展,你可以期望它能够更多地引入新功能。要获取有关规范最新添加的更新,请查看完成的提案【https://github.com/tc39/proposals/blob/master/finished-proposals.md】列表。

https://blog.logrocket.com/what-is-globalthis-why-use-it/

在公众号内回复“体系”查看高清大图

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-12-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端先锋 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
ES2020新特性
ES2020 是 ECMAScript 对应 2020 年的版本。这个版本不像 ES6 (ES2015)那样包含大量新特性。但也添加了许多有趣且有用的特性。
浪里行舟
2020/04/02
6330
ES2020新特性
Javascript 的新功能-Part 1[每日前端夜话0xC6]
最近更新的 V8 引擎使性能提升了不少。JavaScript 解析速度提高了 2 倍甚至更快,从node v8.0开始,node v11以上版本的平均速度比 node v8.0 提高了 11 倍。内存消耗减少了 20%。在性能和可用性上有了全面改善。
疯狂的技术宅
2019/09/25
9480
Javascript 的新功能-Part 1[每日前端夜话0xC6]
es2020 新特性
Javascript 的动态引入,允许你把 JS 文件作为一个模块动态的引入到你的应用中
刘嘿哈
2022/10/25
2560
es2020 新特性
盘点 ES2020 的新功能
Ecma International 负责对 JavaScript 的标准化。是他们制定了 ECMAScript 规范。当提到 ECMAScript 时,基本上可以把它看作是 JavaScript 的同义词。从 2015 年开始,开始用年份标记版本,即 ECMAScript 2015 缩写为 ES2015。但是也会使用版本号的计数,所以 ES6 与 ES2015 相同。尚未发布的功能被称为 ESNext。
疯狂的技术宅
2020/12/15
4530
盘点 ES2020 的新功能
实用的js 技巧之——空值合并运算符、gloabalThis
ES语法并不是一成不变的,从最初的ES5已经到ES12了,了解语言的新特性,可以简化我们的代码写法或者更高效的实现我们的诉求,今天主要介绍以下两个常用的特性:空值合并运算符、globalThis。
前端知知
2022/09/29
1.2K0
ES2020
ES2020(即 ES11)2020 年 6 月已经正式发布,在此之前进入 Stage 4 的 10 项提案均已纳入规范,成为 JavaScript 语言的新特性
4O4
2022/04/25
5780
ES2020
this指向 1 — 全局作用域下的this
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。
用户9914333
2022/07/22
5210
this指向 1 — 全局作用域下的this
ECMAScript 2020新特性
ECMAScript 2020 是 ECMAScript 语言规范的第11版。自1997年出版第一版以来,ECMAScript 已发展成为世界上使用最广泛的通用编程语言之一。
ConardLi
2020/10/30
8320
ECMAScript 2020新特性
ES2020的新特性:String 的 matchAll 方法、动态导入语句 import()等
matchAll() 方法返回一个包含所有匹配正则表达式的结果的迭代器。可以使用 for...of 遍历,或者使用 展开运算符(...) 或者 Array.from 转换为数组.
前端达人
2021/06/16
7280
ES11屡试不爽的新特性,你用上了几个?
严格限制一些用于内部使用的Class变量,只需要在变量前「#」,就可以使其成为私有变量,并且无法在class外部直接访问
Sneaker-前端公虾米
2021/12/23
5990
ES11屡试不爽的新特性,你用上了几个?
ES11 来了,还学得动吗?
ES2020(即 ES11)上周(2020 年 6 月)已经正式发布,在此之前进入 Stage 4 的 10 项提案均已纳入规范,成为 JavaScript 语言的新特性
ayqy贾杰
2020/06/30
6120
ES11 来了,还学得动吗?
【译】JavaScript全局变量的运行机制
在这篇博客中,我们会探究JavaScript全局变量的运行机制。其中,有些有趣的现象将会起到关键作用,如作用域范围、全局对象等等。
腾讯IVWEB团队
2020/06/27
8900
ECMAScript 2020(ES11) 的新特性总结
虽然这套语法已经可以满足绝大多数的导入需求,而且还可以支持实现静态分析以及树抖动等一系列重要的功能。但却无法满足一些需要动态导入的需求。例如:
江一铭
2022/06/16
7050
ECMAScript 2020(ES11) 的新特性总结
ES11屡试不爽的新特性,你用上了几个?
严格限制一些用于内部使用的Class变量,只需要在变量前添加#,就可以使其成为私有变量,并且无法在class外部直接访问
前端公虾米
2020/10/22
7100
ES11屡试不爽的新特性,你用上了几个?
ECMAScript 2020 新增功能速成
ECMAScript 2020 是我们最喜欢的编程语言的第 11 版,其中包含一些新功能。有些是小特性,但有些将会有可能永远改变我们编写 JavaScript 的方式。
疯狂的技术宅
2020/04/24
8370
ECMAScript 2020 新增功能速成
种草 ES2020 新特性,真的学不动了
https://juejin.im/post/5e09ca40518825499a5abff7
coder_koala
2020/02/24
5390
ES2020 中 Javascript 10 个你应该知道的新功能
好消息 - ES2020 新功能已经落地!这就意味着,现在对 ES2020 中 Javascript 的新增和改进要有一个完整的了解。让我们来看看都有哪些改变。
winty
2020/09/22
6290
ES2020 中 Javascript 10 个你应该知道的新功能
📚从ES7到ES12,了解JavaScript的新特性与语法演变
Array.prototype.includes 是一个用于判断数组是否包含特定元素的方法。它返回一个布尔值,表示数组中是否存在指定的值。
linwu
2023/07/27
4430
JS全局变量
我们平时常说的变量的作用域(scope),它全名应该叫「词法作用域」(lexical scope)。它是程序中可以访问变量的区域,即作用域控制着变量和函数的可见性和生命周期。
前端柒八九
2022/08/25
13.6K0
JS全局变量
ES2020 系列:全局对象 globalThis
全局对象提供可在任何地方使用的变量和函数。默认情况下,这些全局变量内置于语言或环境中。
微芒不朽
2022/09/06
7090
ES2020 系列:全局对象 globalThis
相关推荐
ES2020新特性
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验