当前位置: 首页 > Web前端 > HTML5

什么是globalThis,我为什么要学习使用它?

时间:2023-04-05 13:21:01 HTML5

作者:DmitriPavlutin译者:前端小智来源:新闻点赞再看,养成习惯本文已收录在GitHubhttps://github.com/qq44924588...分类,也整理一下我的很多文档和教程材料。欢迎来到星和完美。面试时可参考考点复习。我希望我们能在一起。JS语言越来越多地用于各种上下文中。除了最常见的浏览器,它还可以在服务器、智能手机甚至机器人硬件上运行。每个环境都有自己的对象模型,并提供不同的语法来访问全局对象。例如,在Web浏览器中,可以通过window、self或frames访问全局对象。但是,在Node.js中,这些属性不存在,必须使用global代替。在WebWorker中,只有self可用。这些不同的全局对象引用方式使得JS很难实现跨平台。幸运的是,工作中有一项提案旨在通过引入一个名为globalThis的标准属性来解决这个问题,该属性将在所有环境中可用。在这篇文章中,我们先看看JS环境下的global对象,然后看看globalThis是如何提供一个统一的机制来访问它的。windowwindow属性用于在浏览器环境中引用当前文档的全局对象。在代码的顶层,用var关键字声明的变量将成为window的属性,可以从代码中的任何地方访问:vara=[10,20];console.log(window.a);//→[10,20]console.log(a===window.a);//→true通常,在使用窗口的属性时,不需要直接引用它,因为引用是隐式的。但是,当存在与全局变量同名的局部变量时,使用window是唯一的选择:vara=10;(function(){vara=20;console.log(a);//→20console.log(window.a);//→10})();正如您在上面看到的,无论代码在什么范围内运行,window对于引用全局对象都是有用的。请注意,window实际上引用了它自己:window.window,所以window.window===window。除了标准的JS属性和方法外,窗口对象还包含几个额外的属性和方法,使我们能够控制Web浏览器窗口和文档本身。selfWebWorkersAPI没有Window对象,因为它没有浏览上下文。相反,它提供了WorkerGlobalScope接口,其中包含窗口携带的数据。要访问WebWorkers中的全局对象,我们使用self,它是window对象的同义词。与window类似,self是对全局对象的引用://awebworkerconsole.log(self);//=>DedicatedWorkerGlobalScope{...}vara=10;控制台日志(self.a);//→10console.log(a===self.a);//→true在浏览器环境中,此代码打印窗口对象而不是DedicatedWorkerGlobalScope。由于self的值会根据使用上下文而变化,因此有时它比window更可取。虽然self在webworker上下文中指的是WorkerGlobalScope.self,但它在浏览器上下文中指的是window.self。重要的是不要将self属性与声明局部变量(用于维护对上下文的引用)的常见JS模式混淆。例如constobj={myProperty:10,myMethod:function(){console.log(this===obj);//=>true//将此值存储在变量中以在嵌套函数中使用constself=this;consthelperFunction=(function(){console.log(self===obj);//=>true(self指的是外部的this值)console.log(this===obj);//=>false(this指的是全局对象,在严格模式下,它的值是undefined)})();}};obj.myMethod();frames在浏览器环境中访问全局对象的另一种方法是使用frames属性,它的工作方式类似于self和window://browserenvironmentconsole.log(frames);//=>Window{...}此只读属性通常用于获取当前窗口的子帧列表。例如,我们可以使用window.frames[0]或frames[0]来访问第一帧。global在Node.js中,可以使用global关键字访问全局对象://nodeenvironmentconsole.log(global);//=>Object[global]{...}window、self或frames不在Node环境中启动。请记住,Node.js中的顶级作用域不是全局作用域。在浏览器中,varabc=123将创建一个全局变量。但是,在Node.js中,变量将是模块本身的本地变量。this在浏览器中,可以在程序的顶层使用this关键字来引用全局对象:this.foo=123;console.log(this.foo===window.foo);//=>trueinnon-strictmodethis在下面运行的内部函数或箭头函数中也引用全局对象。但是,对于在严格模式下运行的函数,情况并非如此,其中未定义此值:(function(){console.log(this);//=>Window{...}})();(()=>{console.log(this);//=>Window{...}})();(function(){"usestrict";console.log(this);//=>undefined})();在Node模块中,this不引用顶层的全局对象。相反,它具有与module.exports相同的值。在函数内部(Node环境),this值是根据函数的调用方式确定的。在JS模块中,这在顶层是未定义的。globalThis的引入旨在通过定义一个标准的全局属性来整合日益分散的访问全局对象的方式。该提案目前处于第四阶段,这意味着它已准备好纳入ES2020标准。所有流行的浏览器,包括Chrome71+、Firefox65+和Safari12.1+,都已经支持此功能。您也可以在Node.js12+中使用它。//浏览器环境console.log(globalThis);//=>Window{...}//node.js环境console.log(globalThis);//=>Object[global]{...}//webworker环境console.log(globalThis);//=>DedicatedWorkerGlobalScope{...}通过使用globalThis,您的代码将在窗口和非窗口上下文中工作,而无需编写额外的检查或测试。在大多数环境中,globalThis直接引用环境的全局对象。但是,在浏览器中,内部使用代理来考虑iframe和跨窗口安全性。事实上,它并没有改变我们编写代码的方式。另一方面,如果你确定你的代码将在什么环境中使用,你可以使用现有的方法来引用环境的全局对象,这样你就不必为globalThis包含一个polyfill。创建globalThispolyfill在引入globalThis之前,跨不同环境访问全局对象的常用方法是使用以下模式functiongetGlobalObject(){returnFunction('returnthis')();}if(typeofgetGlobalObject().光热发电)。由于CSP,Chrome的扩展系统也不允许运行此类代码。引用全局对象的另一种模式如下:functiongetGlobalObject(){if(typeofglobalThis!=='undefined'){returnglobalThis;}if(typeofself!=='undefined'){returnself;}if(typeofwindow!=='undefined'){返回窗口;}if(typeofglobal!=='undefined'){returnglobal;}thrownewError('cannotfindtheglobalobject');};if(typeofgetGlobalObject().Promise.allSettled!=='function'){//Promise.allSettled()方法在此环境中不可用}这种模式在网络上很常用。但它也有一些缺陷,使其在某些情况下不可靠。幸运的是,ChromeDevTools的MathiasBynens想出了一个创造性的模式,没有这些缺点:',{get:function(){returnthis;},configurable:true//这使得稍后可以“删除”getter。});__magic__.globalThis=__magic__;//lolwatdeleteObject.prototype.__magic__;}());//你的代码现在可以使用`globalThis`.console.log(globalThis);这种polyfill是比其他方法更可靠的解决方案,但仍不完美。正如Mathias提到的,修改Object、Object.defineProperty或Object.prototype.__defineGetter__可能会破坏polyfill。总结编写可在多种环境中工作的可移植JS代码很困难。每个宿主环境都有一个略有不同的对象模型。因此,要访问全局对象,需要在不同的JS环境下使用不同的语法。通过引入globalThis属性,访问全局对象变得更加简单,并且无需检测代码运行的环境。乍一看,globalThis的实现很简单,但实际操作起来却相当复杂。所有现有的实现都不完美,如果不小心,可能会引入错误。代码部署后可能存在的bug,无法实时获知。事后为了解决这些bug,花费了大量的时间在日志调试上。顺便推荐一个好用的bug监控工具Fundebug。原文:https://news.ycombinator.com/...每周更新交流文章。可以微信搜索“大千世界”阅读即时更新(比博文早一两篇)。这篇文章在GitHub上https://github.com/qq449245884/xiaozhi已经收录,整理了很多我的文档。欢迎明星和完美。面试可以参考考点。也关注公众号,后台就能看到福利了。你说对了。