Определение независимой от реализации версии глобального объекта в JavaScript

Я пытаюсь определить global объект в JavaScript в одну строку следующим образом:

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, и если да, то как я могу это исправить.

В конце концов, я намереваюсь использовать его в лямбда-выражении для моей независимой от реализации структуры JavaScript следующим образом (идея из jQuery):

(function (global) {
    // javascript framework
})(this.global || this);

3 ответа

Решение

Прочитав ответы Эсайлии и Райноса, я понял, что мой код this.global || this не будет работать для всех случаев в node.js; и что он может даже потерпеть неудачу в браузерах, если переменная global уже существует в глобальном масштабе.

Эсайлия указала, что this.global на самом деле не global объект, заявив, что this это global объект в RingoJS; и хотя я понимаю его аргументы, для моих целей я требую this.global и не this,

Рейнос предложил мне жестко определять функции кода для каждой среды CommonJS. Однако, поскольку в настоящее время я поддерживаю только RingoJS и node.js, мне нужно только проверить global а также window, Поэтому я решил придерживаться this.global || this,

Тем не менее, как я уже говорил this.global || this не работает для всех случаев в node.js, как я понял из комментариев Бенви. В REPL node.js я понял, что мне нужно this и не this.global, Тем не мение, 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 чтобы получить global объект как в RingoJS, так и в node.js; и мы используем this как global объект в браузерах (window) и как запасной вариант по умолчанию.

Примечание: я не предоставил никакой логики для нахождения global объект в файле node.js REPL, потому что я не верю, что мой фреймворк в любом случае будет использоваться непосредственно в REPL. Тем не менее, написание логики, чтобы найти его должно быть довольно тривиальным, как только понимаешь сложности поиска global объект в node.js, как указал Бенви. Я знаю, что нет.

this никоим образом не относится к сфере.

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

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

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

this разрешается только во время вызова функции и сводится к нескольким простым правилам.

  1. Если функция вызывается как свойство некоторого объекта, то этот объект будет this внутри функции
  2. Если функция вызывается как есть, this будет неопределенным, поэтому в нестрогом режиме это будет глобальный объект
  3. Если функция вызывается с .call/.apply затем this явно установлено вами.

Таким образом, как вы можете видеть, это подпадает под правило № 2, которое разрешает undefined, А так как нет "use strict";:

установить ThisBinding для глобального объекта

Редактировать: теперь я провел несколько быстрых тестов в RingoJS, и они фактически помещают "глобальный объект" в реальный глобальный объект (как определено стандартами), который ModuleScope, Просто потому, что фактический глобальный объект в большинстве реализаций js имеет Object и String и т. Д., Не делает объект глобальным, если он также содержит эти объекты. Причина, по которой вы можете получить доступ String а также Object в RingoJS, потому что они положили их в 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"

Беги, 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?
);

Вам потребуется жесткий код для обнаружения функций для каждой среды.

Другие вопросы по тегам