[英]How to get the global object in JavaScript?
如果某個其他模塊已加載,我想簽入腳本。
if (ModuleName) {
// extend this module
}
但是如果ModuleName
不存在,則throw
s。
如果我知道Global Object
是什么,我就可以使用它。
if (window.ModuleName) {
// extend this module
}
但是由於我希望我的模塊同時與瀏覽器和node
、 rhino
等一起使用,我不能假設window
。
據我了解,這在帶有"use strict"
ES 5 中不起作用;
var MyGLOBAL = (function () {return this;}()); // MyGlobal becomes null
這也將失敗並拋出異常
var MyGLOBAL = window || GLOBAL
所以看起來我被剩下了
try {
// Extend ModuleName
}
catch(ignore) {
}
這些情況都不會通過 JSLint。
我錯過了什么嗎?
好吧,你可以使用typeof
運算符,如果標識符不存在於作用域鏈的任何地方,它不會拋出ReferenceError
,它只會返回"undefined"
:
if (typeof ModuleName != 'undefined') {
//...
}
還要記住,全局代碼上的this
值是指全局對象,這意味着如果你的if
語句是在全局上下文中,你可以簡單地檢查this.ModuleName
。
關於(function () { return this; }());
技術,你是對的,在嚴格模式下, this
值將只是undefined
。
在嚴格模式下,無論您身在何處,都有兩種方法可以獲取對 Global 對象的引用:
通過Function
構造函數:
var global = Function('return this')();
使用Function
構造函數創建的Function
不繼承調用者的嚴格性,只有當它們以'use strict'
指令開始它們的主體時它們才是'use strict'
,否則它們是非嚴格的。
此方法與任何 ES3 實現兼容。
通過間接eval
調用,例如:
"use strict"; var get = eval; var global = get("this");
以上將起作用,因為在 ES5 中,對eval
間接調用將全局環境用作 eval 代碼的變量環境和詞法環境。
請參閱輸入評估代碼,步驟 1 的詳細信息。
但請注意,最后一個解決方案不適用於 ES3 實現,因為在 ES3 上對eval
的間接調用將使用調用者的變量和詞法環境作為 eval 代碼本身的環境。
最后,您可能會發現檢測是否支持嚴格模式很有用:
var isStrictSupported = (function () { "use strict"; return !this; })();
對於當今所有的 Webpacks 和 Broccolis、Gulps 和 Grunts、TypeScripts 和 AltScripts 以及 create-react-apps 等,這非常無用,但是如果您只是使用普通的、舊的、VanillaJS 並且您想要制作它同構,這可能是你最好的選擇:
var global
try {
global = Function('return this')();
} catch(e) {
global = window;
}
即使在 node 中使用--use_strict
函數構造函數調用也能工作,因為函數構造函數總是在全局非嚴格范圍內執行。
如果 Function 構造函數失敗,那是因為您使用的瀏覽器中的eval
被 CSP 標頭禁用。
當然,隨着 Deno 的進行(節點替換),他們也可能禁止 Function 構造函數,在這種情況下,它會返回到枚舉對象,如global
、 module
、 exports
、 globalThis
和window
,然后進行鴨子類型檢查,這是全球詳盡... :-/
var global = Function('return this')() || (42, eval)('this');
.
.
.
如果最新瀏覽器中的 HTTP 標頭明確禁止 eval,這現在可能會失敗。
一種解決方法是嘗試/捕獲原始解決方案,因為只有瀏覽器才能運行這種類型的 JavaScript 子集。
var global;
try {
global = Function('return this')() || (42, eval)('this');
} catch(e) {
global = window;
}
Example:
---
(function () {
var global = Function('return this')() || (42, eval)('this');
console.log(global);
// es3 context is `global`, es5 is `null`
(function () {
"use strict";
var global = Function('return this')() || (42, eval)('this');
console.log(global);
}());
// es3 and es5 context is 'someNewContext'
(function () {
var global = Function('return this')() || (42, eval)('this');
console.log(global);
}).call('someNewContext');
}());
Tested:
---
* Chrome v12
* Node.JS v0.4.9
* Firefox v5
* MSIE 8
Why:
---
In short: it's some weird quirk. See the comments below (or the post above)
In `strict mode` `this` is never the global, but also in `strict mode` `eval` operates in a separate context in which `this` *is* always the global.
In non-strict mode `this` is the current context. If there is no current context, it assumes the global. An anonymous function has no context and hence in non-strict mode assumes the global.
Sub Rant:
There's a silly misfeature of JavaScript that 99.9% of the time just confuses people called the 'comma operator'.
var a = 0, b = 1;
a = 0, 1; // 1
(a = 0), 1; // 1
a = (0, 1); // 1
a = (42, eval); // eval
a('this'); // the global object
為什么不簡單地在全局范圍內使用 this 作為包裝函數的參數,如下所示?
(function (global) {
'use strict';
// Code
}(this));
干得好 :)
var globalObject = (function(){return this;})();
這應該適用於任何地方,例如在另一個閉包中。
編輯 - 只需更仔細地閱讀您的帖子,並查看有關 ES5 嚴格模式的部分。 任何人都可以對此有所了解嗎? 只要我記得,這一直是獲取全局對象的公認方式......我當然希望它不會最終被破壞。
編輯 2 - CMS 的回答有更多關於 ES5 嚴格模式處理this
。
我認為這在犀牛、節點、瀏覽器和jslint (沒有額外的解決方法標志)中非常好 - 這有幫助嗎? 我錯過了什么嗎?
x = 1;
(function(global){
"use strict";
console.log(global.x);
}(this));
雖然我自己傾向於使用 window 對象,如果我確實需要無頭測試,我可以使用 env.js (rhino) 或 Phantom (node)。
ECMAScript 將很快將其添加到其標准中: https : //github.com/tc39/proposal-global
在完成之前,這是推薦的:
var getGlobal = function () {
// the only reliable means to get the global object is
// `Function('return this')()`
// However, this causes CSP violations in Chrome apps.
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
這不是傳遞 jslint: var Fn = Function, global = Fn('return this')();
自己試試: http : //www.jslint.com/
這將: var Fn = Function, global = new Fn('return this')();
但實際上,根據MDN,它們是相同的:
將 Function 構造函數作為函數調用(不使用 new 運算符)與將其作為構造函數調用具有相同的效果。
以下解決方案適用於:
代碼是:
(function (__global) {
// __global here points to the global object
})(typeof window !== "undefined" ? window :
typeof WorkerGlobalScope !== "undefined" ? self :
typeof global !== "undefined" ? global :
Function("return this;")());
您只需要將 X 更改為您想要的變量名稱
這是我正在使用的:
"use strict";
if(this && this.hasOwnProperty && !this.hasOwnProperty('globalScope')){
try {
globalScope = Function('return this')();
}catch(ex){
if(this.hasOwnProperty('window')){
globalScope = window;
}else{
throw 'globalScope not found';
}
}
}
我以前遇到過這個問題,我對解決方案不滿意,但它可以工作並通過 JSLint(假設瀏覽器|假設節點):
"use strict";
var GLOBAL;
try{
/*BROWSER*/
GLOBAL = window;
}catch(e){
/*NODE*/
GLOBAL = global;
}
if(GLOBAL.GLOBAL !== GLOBAL){
throw new Error("library cannot find the global object");
}
擁有 GLOBAL var 后,您可以進行檢查,並在腳本類型的末尾
delete GLOBAL.GLOBAL;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.