Определение независимой от реализации версии глобального объекта в 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
разрешается только во время вызова функции и сводится к нескольким простым правилам.
- Если функция вызывается как свойство некоторого объекта, то этот объект будет
this
внутри функции - Если функция вызывается как есть,
this
будет неопределенным, поэтому в нестрогом режиме это будет глобальный объект - Если функция вызывается с
.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?
);
Вам потребуется жесткий код для обнаружения функций для каждой среды.