在 JavaScript 中定义全局对象的独立于实现的版本

     2023-03-07     76

关键词:

【中文标题】在 JavaScript 中定义全局对象的独立于实现的版本【英文标题】:Defining an implementation independent version of the global object in JavaScript 【发布时间】:2012-01-06 23:38:27 【问题描述】:

我正在尝试在 JavaScript 中定义 global 对象,如下所示:

var global = this.global || this;

上面的语句是在全局范围内的。因此,在浏览器中,this 指针是window 对象的别名。假设它是在当前网页上下文中执行的第一行 JavaScript,那么global 的值将始终与this 指针或window 对象的值相同。

在 CommonJS 实现中,例如 RingoJS 和 node.js,this 指针指向当前的ModuleScope。但是,我们可以通过ModuleScope 上定义的属性global 访问global 对象。因此我们可以通过this.global 属性访问它。

因此,这段代码 sn-p 适用于所有浏览器,至少适用于 RingoJS 和 node.js,但我还没有测试过其他 CommomJS 实现。因此,我想知道这段代码在任何其他 CommonJS 实现上运行时是否不会产生正确的结果,如果是,我该如何修复它。

最后,我打算在 lambda 表达式中为我的实现独立的 JavaScript 框架使用它,如下所示(来自 jQuery 的想法):

(function (global) 
    // javascript framework
)(this.global || this);

【问题讨论】:

【参考方案1】:

this 与范围无关。

(function()
    (function()
        (function()

            (function()
            alert( this ); //global object
            )()

        ).bind()()
    ).apply()
).call()

this 仅在函数调用期间解析,归结为几个简单的规则。

    如果函数作为某个对象的属性调用,则该对象将在函数内部为this 如果按原样调用函数,this 将未定义,因此在非严格模式下它将是全局对象 如果函数使用.call/.apply 调用,那么this 由您自己显式设置。

如您所见,它属于规则#2,它解析为undefined。而且由于没有"use strict";

将 ThisBinding 设置为全局对象

编辑:我现在在 RingoJS 中进行了一些快速测试,他们实际上将“全局对象”放入了实际的全局对象(由标准定义),即 ModuleScope。仅仅因为大多数 js 实现中的实际全局对象都有 Object 和 String 等,如果它下面也有这些对象,则不会使对象成为全局对象。在 RingoJS 中可以访问 StringObject 的原因是因为它们将它们放入了 ModuleScope 原型中:

var logs = require('ringo/logging').getLogger("h");

logs.info( Object.getPrototypeOf( this ) === this.global );
//true

进一步证明ModuleScope 是实际的全局对象:

this.property = "value";
logs.info( property );
//"value"

所以这种诡计没有任何收获,它不能解决任何问题:

function injectGlobal()
globalProperty = "value"; // "use strict" would fix this!


injectGlobal()

logs.info( globalProperty );
//"value"

吐槽,this 已经根据本文前面给出的规则指代了实际的全局对象。 this.global 不是标准定义的真正的全局对象,它只是一个容器。

此外,您可以在浏览器中模拟这种行为:

考虑 scopehack.js

this.global = window.global || top.global || ;

考虑 main.html:

<script src="scopehack.js"></script>
<script>
this.global.helloWorld = "helloWorld"; //"global scope"
this.helloWorld = "helloWorld" //"ModuleScope"
</script>

<iframe src="module.html"></iframe>

最后是一个“模块”module.html:

<script src="scopehack.js"></script>
<script>
    with( this.global )  //poor mans RhinoJS scope injection, doesn't work for writing
        console.log( helloWorld ); //"global scope" - "helloWorld"
        console.log( this.helloWorld ); //"ModuleScope" undefined
    
</script>

module.html 和 main.html 中哪个是实际的全局对象?它仍然是this

TLDR:

var obj = 
"String": String,
"Object": Object,
.....
;

不使 obj 成为全局对象。

【讨论】:

这很好,但我已经知道了。这就是我在代码中使用 this 而不是 window 的原因 - 它适用于所有 JavaScript 实现。然而,在 RingoJS 和 node.js 中,this 指针并不指向global 对象。它指向ModuleScope。因此我不得不写this.global || this。这不是我所期望的答案。对不起。 =( @AaditMShah,对。 this.globalthis 一样好,因为如果global 是一个全局变量,那么this 也必须是全局变量,this.global 才能工作。你可以在任何地方使用global,除非它在本地被覆盖,否则它将解析为全局对象......我不太明白你的问题是什么:( 顺便说一句,当我说“上述语句在全局范围内。因此在浏览器中,this 指针是window 对象的别名。”,我试图传达这一点它没有写在函数内部,因此它只能是window 对象(规则#1 和#3 不适用)。就我而言,规则 #2 也部分不正确,因为 this 指针不在函数内。当我们在全局上下文中使用 this 时,它在浏览器中始终是 window 对象,仅此而已。 @Esailija - 真的很难解释。看,this.global 是一个指向 global 对象的局部变量,this.global !== this 将返回 true 因为在 RingoJS 和 node.js 中,this 指针永远不会指向 global 对象(就像你规则#2)。相反,它指向ModuleScope。在ModuleScope 上有一个名为global 的属性,它指向global 对象。无法像在浏览器环境中那样直接访问 global 对象。 @AaditMShah,在模块内你可以尝试做:var a = (function()return this;)(); a 仍然是模块对象吗?根据 javascript 规范,它应该是未定义的或全局的。【参考方案2】:

实现独立版本并非易事

(function (global) 
    // javascript framework
)(
   this && this.global || // ringoJS
   typeof root !== "undefined" && root || // node.js
   typeof global !== "undefined" && global || // more node.js
   typeof GLOBAL !== "undefined" && GLOBAL || // more node.js
   typeof window !== "undefined" && window || // browsers
   this // either undefined or some global default?
);

您将不得不对每个环境的特征检测进行硬编码。

【讨论】:

root 是 Node 中的实际全局对象。 @AaditMShah 不,不是。 this || this.global 将返回 this 而不是 this.global root === GLOBAL 应该始终为真。 root === global 将取决于您当前所处的上下文。例如,在 REPL 中,如果您在全局上下文中运行,那么它是正确的,否则它不是。 这实际上是一个非常重要的区别,因为它改变了当你做扩展原生原型之类的事情时发生的事情。如果您不在全局上下文中,root.Object 将返回 undefined,但如果您在,那么它将指向包含所有 Node 对象继承的 Object.prototypeObjectthis 也可以指向完全任意的东西,而不是 rootglobalGLOBAL,或者它可以指向 root 据我所知,这在任何地方都没有记录,但是 Node 的大部分代码是用 JavaScript 实现的,所以它很容易上手。相关的代码位是github.com/joyent/node/blob/master/lib/module.js#L394github.com/joyent/node/blob/master/src/node.js#L125github.com/joyent/node/blob/master/src/node_script.cc#L112【参考方案3】:

阅读 Esailija 和 Raynos 的回答后,我了解到我的代码 this.global || this 不适用于 node.js 中的所有情况;如果全局范围内已经存在名为 global 的变量,它甚至可能在浏览器中失败。

Esailija 指出this.global 并不是真正的global 对象,而是指出this 是RingoJS 中的global 对象;虽然我理解他的论点,但出于我的目的,我需要this.global 而不是this

Raynos 建议我为每个 CommonJS 环境硬编码特征检测。但是由于我目前只支持 RingoJS 和 node.js,我只需要测试 globalwindow。因此我决定坚持使用this.global || this

尽管如此,正如我之前所说,this.global || this 并不适用于 node.js 中的所有情况,正如我从 benvie 的 cmets 中了解到的那样。在 node.js REPL 中,我意识到我需要 this 而不是 this.global。但是,this.global || this 表示 this.global。在 node.js 模块中,我需要 this.global 而不是 this。但是,它表示this,因为this.globalundefined。因此,为了解决这个问题,我最终决定使用以下代码:

(function (global) 
    // javascript framework
)(typeof global !== "undefined" && global || this);

我使用此代码的原因是因为在 node.js 模块中 this.globalundefined。因此我们必须直接使用global。因此我们使用typeof global !== "undefined" &amp;&amp; global 来获取RingoJS 和node.js 中的global 对象;我们使用 this 作为浏览器中的 global 对象 (window) 并作为默认后备。

注意:我没有提供在 node.js REPL 中查找 global 对象的任何逻辑,因为我不相信我的框架会直接在 REPL 中使用。然而,一旦理解了在 node.js 中查找global 对象的复杂性,正如本维指出的那样,编写查找它的逻辑应该是相当简单的。我知道我没有。

【讨论】:

javascript中的全局对象,内置对象和预定义对象是啥?

RT1.全局对象是预定义的对象,作为 JavaScript 的全局函数和全局属性的占位符。  通过使用全局对象,可以访问所有其他所有预定义的对象、函数和属性。  全局对象不是任何对象的属性,所以它没有名称。2.内部对象是编写... 查看详情

全局对象

定义:  全局对象(globalobject)在JavaScript中有着重要的用途,全局对象的属性是全局定义的符号,JavaScript可以直接使用,比如:全局属性undefined,infinity和NaN全局函数isNaN(),parseINt(),eval())构造函数Date(),RegExp()... 查看详情

javascript篇-----执行环境和作用域

  执行环境是javascript中最为重要的一个概念。执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。  ... 查看详情

javascript面向对象及相关知识

最近在学习JavaScript面向对象,写下自己的理解及相关资料,以备查阅。一.面向对象中涉及的相关几个概念 1.作用域  所谓作用域,就是说属性和函数的可访问范围。在JavaScript中,作用域分为两种。全局作用域和局部作用域... 查看详情

nj08---processconsole

...所有属性都可以在程序的任何地方访问,即全局变量。在JavaScript中,通常window是全局对象,而Node.js的全局对象是global,所有全局变量都是global对象的属性,如:console、process等。一、全局对象与全局变量global最根本的作用是作... 查看详情

惊讶于全局变量在 JavaScript 中具有未定义的值

】惊讶于全局变量在JavaScript中具有未定义的值【英文标题】:SurprisedthatglobalvariablehasundefinedvalueinJavaScript【发布时间】:2012-02-2313:03:07【问题描述】:今天,当我看到一个全局变量在某种情况下具有undefined值时,我感到非常惊讶... 查看详情

javascript基础_04对象与函数

1变量作用域和作用域链作用域:指的是变量和函数的访问范围,也就是说作用域控制着变量的可见性和生命周期,包括局部作用那个与和全局作用域;局部作用域:指的是一般只在固定代码片内可以访问的作用域,常见的在函... 查看详情

javascript之执行环境及作用域

   执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。我们编写的代码是无法访问这个对象的,... 查看详情

访问 javascript 文件中的全局 Qt 对象,QML

】访问javascript文件中的全局Qt对象,QML【英文标题】:AccessglobalQtobjectinjavascriptfile,QML【发布时间】:2018-10-1312:41:59【问题描述】:我在我的一个QML文件中定义了这个创建组件并检查它是否准备就绪的javascript函数:Itemid:libfunctionc... 查看详情

javascript作用域

作用域是可访问变量的集合。在JavaScript中,能够定义全局作用域或者局部作用域。在JavaScript中,对象和函数同样也是变量。在JavaScript中,作用域为可访问变量,对象,函数的集合。JavaScript函数作用域:作用域在函数内... 查看详情

javascript基础对象函数

对象的简介string字符串,number数值,Boolean布尔值,null空值,undefined未定义。以上这五种类型属于基本数据类型,以后我们看的值只要不是上边的五种,全都是对象。Object对象如果使用基本数据类型的数据,我们所创建的变量都... 查看详情

javascript中this的用法

this的指向this是js中定义的关键字,它自动定义于每一个函数域内,但是它的指向却让人很迷惑。在实际应用中,this的指向大致可以分为以下四种情况。1.作为普通函数调用当函数作为一个普通函数被调用,this指向全局对象。在... 查看详情

将 JavaScript 对象初始化为全局对象,然后在 Iframe 中使用

】将JavaScript对象初始化为全局对象,然后在Iframe中使用【英文标题】:InitializeJavaScriptobjectasglobalobjectforthenuseinIframe【发布时间】:2021-10-1920:28:09【问题描述】:我有一个需要初始化的类。classROSstaticinit()//dorosinitializationROS.ros=new... 查看详情

javascript概念总结:作用域闭包对象与原型链

1 JavaScript变量作用域1.1函数作用域没有块作用域:即作用域不是以{}包围的,其作用域完成由函数来决定,因而if/for等语句中的花括号不是独立的作用域。如前述,JS的在函数中定义的局部变量只对这个函数内部可见,称之谓... 查看详情

bom--window对象

1.在浏览器中,window对象即是通过JavaScript访问浏览器窗口的一个接口,又是ECMAscript规定的Global对象,这意味着在网页中的任何一个对象,变量和函数,都是以window作为其global对象。2.定义全局变量和直接在window上定义属性还是有... 查看详情

Javascript - 在对象中存储函数 - 不好的做法? [关闭]

】Javascript-在对象中存储函数-不好的做法?[关闭]【英文标题】:Javascript-Storingfunctioninobject-badpractice?[closed]【发布时间】:2012-02-1217:35:12【问题描述】:将函数存储在对象中而不是仅仅定义它们(因此是全局的)是否被认为是不... 查看详情

R编辑在父环境中定义的全局对象

】R编辑在父环境中定义的全局对象【英文标题】:Reditingglobalobjectdefinedinparentenvironment【发布时间】:2015-04-1508:07:48【问题描述】:我想编辑在父函数中定义的数据框dat,就像在示例中一样,但是输出(从main返回)给出了一个未... 查看详情

详解javascript中this的工作原理

在JavaScript中this常常指向方法调用的对象,但有些时候并不是这样的,本文将详细解读在不同的情况下this的指向。一、指向window:在全局中使用this,它将会指向全局对象,因为浏览器中运行的JavaScript的全局对象默认为window,所... 查看详情