Próbuję zdefiniować obiekt global w JavaScript w jednej linii w następujący sposób:

var global = this.global || this;

Powyższe oświadczenie jest w zakresie globalnego. Stąd w przeglądarkach this wskaźnik jest alias dla obiektu window. Zakładając, że jest to pierwszy wiersz JavaScript, który ma zostać wykonany w kontekście bieżącej strony internetowej, wartość global będzie zawsze taka sama jak wskaźnik this lub window obiekt.

W implementacjach Commono, takich jak Ringojs i Node.js this Wskaźnik wskazuje na bieżący ModuleScope. Jednak możemy uzyskać dostęp do obiektu global przez właściwość global zdefiniowany na ModuleScope. Dlatego możemy uzyskać do niego dostęp za pośrednictwem nieruchomości this.global.

Stąd ten fragment kodu działa we wszystkich przeglądarkach oraz w przynajmniej Ringojs i Node.js, ale nie przetestowałem innych implementacji Commajs. W ten sposób chciałbym dowiedzieć się więc, czy ten kod nie przyniesie poprawnych wyników po uruchomieniu w dowolnej innej implementacji CommanoS, a jeśli tak, jak mogę to naprawić.

W końcu zamierzam używać go w wyrażeniu lambda dla moich wdrażania niezależnych ram JavaScript w następujący sposób (pomysł z jQuery):

(function (global) {
    // javascript framework
})(this.global || this);
6
Aadit M Shah 26 listopad 2011, 21:14

3 odpowiedzi

Najlepsza odpowiedź

Po przeczytaniu odpowiedzi ESailija i Raynos zrozumiałem, że mój kod this.global || this nie będzie działał dla wszystkich przypadków w węźle. I że może nawet zawieść w przeglądarkach, jeśli zmienna o nazwie global już istnieje w globalnym zakresie.

Esaija wskazała, że this.global nie jest naprawdę obiektem global, stwierdzając, że this jest obiektem global w Ringojs; I choć rozumiem jego argumenty, dla moich celów wymaga this.global, a nie this.

Raynos zaproponowali, że trudno jest wykryć wykrywanie kodu dla każdego środowiska CommonJS. Jednak ponieważ obecnie wspieram tylko ringojs i węzeł.js, muszę tylko testować dla global i window. Stąd postanowiłem trzymać się this.global || this.

Niemniej jednak, jak powiedziałem przed this.global || this nie działa dla wszystkich przypadków w węźle.js, jak rozumiem z uwag Benvie. W node.js Repen zdałem sobie sprawę, że wymagam this, a nie this.global. Jednak this.global || this wyraża this.global. W module node.js wymaga this.global i nie this. Jednak wyraża this od this.global undefined. Dlatego rozwiązać ten problem, w końcu postanowiłem użyć następującego kodu:

(function (global) {
    // javascript framework
})(typeof global !== "undefined" && global || this);

Powodem, dla którego używam tego kodu, jest dlatego, że w moduły node.js this.global to undefined. Dlatego musimy bezpośrednio użyć global. Tak więc używamy typeof global !== "undefined" && global, aby uzyskać obiekt global w obu ringojs i węzeł.js; I używamy this jako obiekt global w przeglądarkach ({x7}}) i jako domyślny fallback.

Uwaga: Nie udostępniałem żadnej logiki do znalezienia obiektu {x0}} w node.js Repen, ponieważ nie wierzę, że moje ramy zostaną wykorzystane bezpośrednio w ramach REP. Jednak pisanie logiki do znalezienia, powinno być dość trywialne, gdy ktoś rozumie komplikacje znalezienia obiektu global w węzła Wiem, że nie.

1
Aadit M Shah 2 grudzień 2011, 07:00

this nie jest w żaden sposób istotny dla zakresu.

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

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

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

this jest rozwiązany tylko podczas połączenia funkcji i sprowadza się do kilku prostych zasad.

  1. Jeśli funkcja zostanie wywołana jako właściwość niektórych obiektu, to obiekt będzie this wewnątrz funkcji
  2. Jeśli funkcja jest nazywana tak, jak jest, this będzie niezdefiniowana, więc w trybie nierentowalnym będzie obiektem globalnym
  3. Jeśli funkcja jest wywoływana .call/.apply this jest wyraźnie ustawiony przez siebie.

Tak więc, jak widać, upadłoby to pod rządami # 2, co rozwiązuje się do undefined. A ponieważ nie ma "use strict";:

Ustaw ten obiekt na globalnym obiekcie

Edytuj: Prowadziłem teraz kilka szybkich testów w Ringojs, a oni indeksują umieścić "globalny obiekt" wewnątrz rzeczywistego obiektu globalnego (zgodnie z definicją standardami), który jest ModuleScope. Tylko dlatego, że rzeczywisty obiekt globalny w większości implementacji JS ma obiekt i łańcuch i tak dalej, nie tworzy obiektu globalnego, jeśli ma te obiekty pod nią również. Powód, dla którego możesz uzyskać dostęp String i Object w Ringojs jest dlatego, że umieścili je w prototypie ModuleScope:

var logs = require('ringo/logging').getLogger("h");

logs.info( Object.getPrototypeOf( this ) === this.global );
//true

Dalszy dowód, że ModuleScope jest rzeczywistym obiektem globalnym:

this.property = "value";
logs.info( property );
//"value"

Więc nic nie jest zdobyte z tego rodzaju oszustwa, nic nie naprawia:

function injectGlobal(){
globalProperty = "value"; // "use strict" would fix this!
}

injectGlobal()

logs.info( globalProperty );
//"value"

Rant nad, this odnosi się do rzeczywistego obiektu globalnego już zgodnie z zasadami podanymi wcześniej w tym poście. this.global nie jest prawdziwym obiektem globalnym określonym przez normy, to tylko pojemnik.

Dodatkowo można naśladować to zachowanie w przeglądarkach:

Rozważ supyhack.js.

this.global = window.global || top.global || {};

Rozważmy Main.HTML:

<script src="scopehack.js"></script>
<script>
this.global.helloWorld = "helloWorld"; //"global scope"
this.helloWorld = "helloWorld" //"ModuleScope"
</script>

<iframe src="module.html"></iframe>

I wreszcie moduł "moduł ".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>

Który jest rzeczywistym obiektem globalnym zarówno w module.html, jak i main.html? Nadal jest this.

TLDR:

var obj = {
"String": String,
"Object": Object,
.....
};

Nie robi obj globalnego obiektu.

5
Esailija 29 listopad 2011, 16:33

Wersja niezależna nie jest trywialna

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

Wystarczy mieć trudny kod w wykrywaniu funkcji dla każdego środowiska.

2
Raynos 30 listopad 2011, 13:33