在JavaScript中定义全局对象的实现独立版本
我试图用JavaScript来定义global
对象,如下所示:
var global = this.global || this;
以上声明在全球范围内。 因此,在浏览器中, this
指针是window
对象的别名。 假设它是在当前网页上下文中执行的第一行JavaScript, global
的值将始终与this
指针或window
对象的值相同。
在CommonJS实现中,如RingoJS和node.js, this
指针指向当前的ModuleScope
。 但是,我们可以通过在ModuleScope
上定义的global
属性来访问global
对象。 因此,我们可以通过this.global
属性来访问它。
因此,这个代码片段适用于所有的浏览器,至lessRingoJS和node.js,但我没有testing其他的CommomJS实现。 因此,我想知道这个代码在其他CommonJS实现上运行时是否会产生正确的结果,如果有的话,我可以如何解决这个问题。
最后,我打算在一个lambdaexpression式中为我的实现独立的JavaScript框架使用它(如下所示)(来自jQuery的想法):
(function (global) { // javascript framework })(this.global || this);
this
与范围无关。
(function(){ (function(){ (function(){ (function(){ alert( this ); //global object })() }).bind({})() }).apply({}) }).call({})
this
只能在函数的调用时间内解决,并归结为一些简单的规则。
- 如果该函数被称为某个对象的属性,那么该对象将在函数内部
- 如果这个函数被调用,
this
将是未定义的,所以在非严格模式下它将是全局对象 - 如果使用
.call/.apply
调用该函数,那么this
是您自己明确设置的。
所以,正如你所看到的那样,它将归属于规则2,这个规则解决了undefined
。 而且由于没有"use strict";
:
将ThisBinding设置为全局对象
编辑:我现在已经在RingoJS中进行了一些快速testing,并且他们实际上把“全局对象”放在实际的全局对象(由标准定义)内,这是ModuleScope
。 仅仅因为大多数js实现中的实际全局对象都具有Object和String等,如果它们也包含这些对象,则不会使对象成为全局对象。 您可以访问RingoJS中的String
和Object
的原因是因为他们把它们放到ModuleScope
原型中:
var logs = require('ringo/logging').getLogger("h"); logs.info( Object.getPrototypeOf( this ) === this.global ); //true
进一步certificateModuleScope
是实际的全局对象:
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”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
成为全局对象。
实现独立版本不是微不足道的
(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? );
您将不得不在每个环境的function检测硬编码。
在阅读Esailija和Raynos的答案后,我明白了我的代码this.global || this
this.global || this
将不适用于node.js中的所有情况; 而且如果一个名为global
的variables已经存在于全局范围内,它甚至可能会在浏览器中失败。
Esailija指出, this.global
并不是真正的global
对象,而是表示this
是RingoJS中的global
对象; 虽然我理解他的论点,但为了我的目的,我需要this
this.global
而不是this
。
Raynosbuild议我对每个CommonJS环境进行硬编码特征检测。 不过由于我目前只支持RingoJS和node.js,我只需要testingglobal
和window
。 因此我决定坚持使用this.global || this
this.global || this
。
不过,正如我之前this.global || this
this.global || this
并不适用于node.js中的所有情况,正如我从benvie的评论中所理解的那样。 在node.js REPL中我意识到我需要this
而不是this.global
。 但是, this.global || this
this.global || this
表示this.global
。 在node.js模块中,我需要this.global
而不是this
。 但是,它表示this
因为this.global
是undefined
。 因此,为了解决这个问题,我终于决定使用下面的代码:
(function (global) { // javascript framework })(typeof global !== "undefined" && global || this);
我使用这个代码的原因是因为在node.js模块中this.global
是undefined
。 因此我们必须直接使用global
。 因此,我们使用typeof global !== "undefined" && global
获取RingoJS和node.js中的global
对象; 我们使用this
作为浏览器( window
)中的global
对象,并作为默认的回退。
注意:我没有提供任何逻辑来查找node.js REPL中的global
对象,因为我不相信我的框架将直接在REPL中使用。 然而,正如Benvie指出的那样,一旦理解了在node.js中查找global
对象的复杂性,编写逻辑来find它应该是相当简单的。 我知道我不知道