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

时间:2011-11-26 17:14:43

标签: javascript jquery node.js global commonjs

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

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);

3 个答案:

答案 0 :(得分:5)

this与范围无关。

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

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

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

this仅在函数的调用时间内解析,并归结为一些简单的规则。

  1. 如果函数被调用为某个对象的属性,那么该对象将在函数内部this
  2. 如果按原样调用该函数,this将是未定义的,因此在非严格模式下它将是全局对象
  3. 如果使用.call/.apply调用该函数,则this由您自己明确设置。
  4. 正如您所看到的,它将属于规则#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成为全局对象。

答案 1 :(得分: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?
);

您需要为每个环境进行功能检测的硬编码。

答案 2 :(得分:1)

在阅读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的评论中所理解的那样。在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" && global来获取RingoJS和node.js中的global对象;我们在浏览器(this)中使用global作为window对象,并作为默认回退。

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