Как получить глобальный объект в JavaScript?

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

if (ModuleName) {
    // extend this module
}

но если ModuleName не существует, что throws.

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

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

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

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

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

это будет не исключение

var MyGLOBAL = window || GLOBAL

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

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

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

я что-нибудь пропустил?

10 ответов


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

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

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

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

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

  • до Function конструктора:

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

функции, созданные с помощью Function конструктор не наследует строгость вызывающего, они строги, только если они начинают свое тело с


сумасшедшее однострочное решение:

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

``

пример:

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

}());

проверил:

  • хром V12 объемом
  • узел.С JS версии v0.4.9
  • в Firefox У5
  • MSIE 8

почему:

короче говоря: это какая-то странная причуда. См. комментарии ниже (или сообщение выше)

на strict mode this никогда не глобальный, но также в strict mode eval работает в отдельном контексте, в котором this is всегда глобальные.

в нестрогом режиме this - это текущий контекст. Если нет текущего контекста, он предполагает глобальный. Анонимная функция не имеет контекста и, следовательно, в нестрогом режиме принимает глобальный.

Sub Rant:

существует глупая неправильность JavaScript, что 99,9% времени просто путает людей, называемых запятыми оператор".

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

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

(function (global) {
    'use strict';
    // Code
}(this));

здесь вы идете :)

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

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

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

Edit 2-Ответ CMS имеет больше информации о обработке строгого режима ES5 this.


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

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

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


у меня была эта проблема раньше, я не доволен решением, но он работает и передает 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");
}

после того, как у вас есть глобальный var, вы можете сделать свою проверку, и в конце типа скрипта

delete GLOBAL.GLOBAL;

это не передача jslint:var Fn = Function, global = Fn('return this')();

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

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

но фактически это одно и то же в соответствии с MDN:

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


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

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

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

Это решение работает в:

  • Chrome
  • узел.JS
  • Firefox
  • MSIE
  • Веб-Работников

код:

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