6

我试图global在单行中定义 JavaScript 中的对象,如下所示:

var global = this.global || this;

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

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

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

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

(function (global) {
    // javascript framework
})(this.global || this);
4

3 回答 3

5

this与范围无关。

(function(){
    (function(){
        (function(){

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

        }).bind({})()
    }).apply({})
}).call({})

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

  1. 如果函数作为某个对象的属性被调用,那么该对象将this在函数内部
  2. 如果函数按原样调用,this将是未定义的,因此在非严格模式下它将是全局对象
  3. 如果调用该函数,.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"

Rant over,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生成全局对象。

于 2011-11-26T17:18:44.600 回答
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?
);

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

于 2011-11-29T15:19:19.443 回答
1

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

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

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

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

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

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

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

于 2011-12-02T07:00:26.003 回答