Как получить глобальный объект в JavaScript? - PullRequest
73 голосов
/ 19 июля 2010

Я хочу проверить в скрипте, если какой-то другой модуль уже загружен.

if (ModuleName) {
    // extend this module
}

Но если ModuleName не существует, то throw с.

Если бы я знал, что такое Global Object, я мог бы использовать это.

if (window.ModuleName) {
    // extend this module
}

Но поскольку я хочу, чтобы мой модуль работал с обоими браузерами и node, rhino и т. Д., Я не могу предположить, что window.

Насколько я понимаю, это не работает в ES 5 с "use strict";

var MyGLOBAL = (function () {return this;}()); // MyGlobal becomes null

Это также не удастся, за исключением брошенного исключения

var MyGLOBAL = window || GLOBAL

Похоже, я остался с

try {
    // Extend ModuleName
} 
catch(ignore) {
}

Ни один из этих случаев не пройдет JSLint.

Я что-то упустил?

Ответы [ 10 ]

90 голосов
/ 19 июля 2010

Ну, вы можете использовать оператор typeof, и если идентификатор не существует ни в одном месте цепочки областей действия, он не выдает ReferenceError, он просто вернет "undefined":

if (typeof ModuleName != 'undefined') {
  //...
}

Помните также, что значение this в глобальном коде относится к глобальному объекту, а это означает, что если ваш оператор if находится в глобальном контексте, вы можете просто проверить this.ModuleName.

По поводу техники (function () { return this; }()); вы правы, в строгом режиме значение this будет просто равно undefined.

В строгом режиме есть два способа получитьссылка на глобальный объект, где бы вы ни находились:

  • через конструктор Function:

    var global = Function('return this')();
    

Функции, созданные с помощьюКонструктор Function не наследует строгость вызывающей стороны, они строгие, только если они начинают свое тело с директивы 'use strict', в противном случае они не являются строгими.

Этот метод совместим с любым ES3реализация.

  • через косвенныйeval вызов , например:

    "use strict";
    var get = eval;
    var global = get("this");
    

Выше будет работать, потому что в ES5, косвенные вызовы eval, используют глобальную среду как переменная среда и лексическая среда для eval-кода.

Подробнее см. Ввод Eval-кода , Шаг 1.

Но помните, что последнее решениене будет работать в реализациях ES3, потому что косвенный вызов eval в ES3 будет использовать переменную и лексическую среду вызывающей стороны в качестве среды для самого кода eval.

И, наконец, вы можете найти полезнымопределить, поддерживается ли строгий режим:

var isStrictSupported = (function () { "use strict"; return !this; })();
21 голосов
/ 03 августа 2011

Обновление 2019

Со всеми сегодняшними Webpacks и Broccolis, а также с Gulps and Grunts, TypeScripts и AltScripts, а также с приложениями create-реагировать и т. Д., Это довольно бесполезно, но если вы просто работаете с простым, старым, VanillaJS и вы хочу сделать его изоморфным, это, вероятно, ваш лучший вариант:

var global
try {
  global = Function('return this')();
} catch(e) {
  global = window;
}

Вызов конструктора функции будет работать даже при использовании --use_strict в узле, поскольку конструктор функции всегда выполняется в глобальной нестрогой области.

Если конструктор Function завершается ошибкой, это потому, что вы находитесь в браузере с eval, отключенным заголовками CSP.

Конечно, с Deno в пути (замена узла) они также могут запретить конструктор Function, и в этом случае он возвращается к перечислению таких объектов, как global, module, exports, globalThis и window, а затем проверка типа утки, которая является глобальной ...: - /

Безумное однострочное решение (Оригинал):

var global = Function('return this')() || (42, eval)('this');

.

.

.

Работает

  • в каждой среде (которую я тестировал)
  • в строгом режиме
  • и даже во вложенной области

Обновление 2014-сентябрь-23

Теперь это может завершиться ошибкой, если заголовки 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
5 голосов
/ 02 октября 2013

Почему бы просто не использовать это в глобальной области видимости в качестве параметра функции-оболочки, как показано ниже

2 голосов
/ 02 августа 2012

Я думаю, что это нормально для носорога, узла, браузера и для jslint (без дополнительных обходных флагов) - это поможет?Я что-то упускаю?

x = 1;
(function(global){
    "use strict";
    console.log(global.x);
}(this));

Хотя я сам склонен использовать объект окна и, если мне нужно тестирование без головы, я могу использовать env.js (носорог) или Phantom (узел).

2 голосов
/ 19 июля 2010

Вот, пожалуйста:)

var globalObject = (function(){return this;})();

Это должно работать из любого места, например из другого замыкания.

Редактировать - просто прочитайте ваш пост более внимательно и посмотрите часть о строгом режиме ES5. Кто-нибудь может пролить немного света на это? Насколько я помню, это был общепринятый способ получить глобальный объект ... Я очень надеюсь, что он не сломается.

Редактировать 2 - в ответе CMS содержится более подробная информация о режиме строгого режима ES5, равном this.

1 голос
/ 29 сентября 2018

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');
};
1 голос
/ 07 августа 2013

Это не проходит jslint: var Fn = Function, global = Fn('return this')();

Попробуйте сами: http://www.jslint.com/

это будет: var Fn = Function, global = new Fn('return this')();

Но по сути это одно и то же согласно MDN :

Вызов конструктора Function как функции (без использования оператора new) имеет тот же эффект, что и вызов его конструктора.

1 голос
/ 28 июля 2011

У меня была эта проблема раньше, я не доволен решением, но оно работает и передает 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;
0 голосов
/ 21 октября 2015

Это следующее решение работает в:

  • Chrome
  • Node.js
  • Firefox
  • MSIE
  • Web Workers

Код:

(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 на имя переменной, которую вы хотели бы

0 голосов
/ 05 февраля 2015

Вот что я использую:

"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';
        }
    }
}
...