2016-01-17 9 views
22

Mam ten fragment kodu:z „to” słowo kluczowe zachowuje się inaczej w Nodejs i przeglądarki

var obj1; 
var obj2; 

function x() { 
    obj1 = this; 
} 

function y() { 
    obj2 = this; 
} 

x(); 
y(); 

console.log(obj1 === obj2); 
console.log(obj1 === this); 

wpadłem ten kod w NodeJS za pomocą linii komend: app.js węzłów i prowadził jako skrypt w przeglądarce Chrome

rezultat: w NodeJS, wynik był: true false NodeJS result

w przeglądarce Chrome, wynik był: true true Browser result

Jak to się stało? Czy ktoś może wyjaśnić, co naprawdę dzieje się pod maską?

+0

możesz chcieć wydrukować "to", aby zobaczyć, co to jest. W przeglądarce powinno być domyślnie 'window', w węźle nie jestem pewien co to jest. – tkausl

Odpowiedz

3

W kontekście przeglądarki ostatni wskazuje ten obiekt, który istnieje w kontekście węzła. Dlatego ostatni to pusty obiekt. Występowanie tego w funkcjach wskazuje jednak na jakiś globalny obiekt w kontekście węzła.

2

różnica jest bardzo prosty

W otoczeniu węzła:

to dotyczy module.exports lub exports za krótki. ale wewnątrz funkcji ta odnosi się do całego pakietu Node.js.

widać to, jeśli użytkownik loguje się do konsoli, co następuje:

function test(){ 
    console.log('this inside a function = ',this); 
} 

console.log('this outside a function = ',this); 
test(); 

Natomiast w środowisku przeglądarki to wewnątrz funkcji lub poza funkcją odnosi się do obiektu okna chyba że jesteś za pomocą nowego słowa kluczowego nowe.

Wykonaj poprzedni przykład w obu Node.js i środowiskach przeglądarkowych, a zrozumiesz.

+1

W trybie ścisłym - to byłoby niezdefiniowane w funkcji –

2

nie mam serwer node.js w dłoni teraz, ale myślę, że można samemu zbadać tę kwestię i dać odpowiedź dla nas: D zobaczyć kod poniżej

próby uruchomienia:

console.log(this.constructor.name+" "+obj1.constructor.name+" "+obj2.constructor.name);

a także można debugować „klasa dominująca” nazwę w funkcję:

function x() { 
    console.log("x this: "+this.constructor.name); 
    obj1 = this; 
} 

function y() { 
    console.log("y this: "+this.constructor.name); 
    obj2 = this; 
} 

a dla widoku obiektu metod/właściwości można korzystać z niektórych coś takiego:

for (a in obj2) { 
    console.log("obj2." + a + " = " + obj2[a]); 
} 
26

W przeglądarce działa w zasięgu globalnym, this jest zawsze window w przykładzie

var obj1; 
var obj2; 

function x() { 
    obj1 = this; // window 
} 

function y() { 
    obj2 = this; // window 
} 

x(); 
y(); 

console.log(obj1 === obj2); // window === window = true 
console.log(obj1 === this); // window === window = true 

To nie jest, jak to działa w węźle. W węźle.js wszystkie moduły (pliki skryptów) są wykonywane we własnym closure, podczas gdy przeglądarki wykonują wszystkie pliki skryptów bezpośrednio w zasięgu globalnym.

Innymi słowy, w prawie każdym pliku uruchomionym w węźle, this będzie po prostu pustym obiektem, ponieważ Węzeł zawija kod w anonimowej funkcji, która jest wywoływana natychmiast, a Ty uzyskasz dostęp do globalnego zakresu w tym kontekście zamiast tego z GLOBAL.

to również wspomniane w Globals documentation:

Niektóre z tych obiektów nie są rzeczywiście w zasięgu globalnym, ale w zakresie modułu - zostanie to odnotowane.

Jednak, gdy wywołanie funkcji bez konkretnego kontekstu node.js, to będzie zazwyczaj domyślnie do globalnego obiektu - To samo GLOBAL wspomniano wcześniej, jak to kontekst wykonania.

Tak więc poza funkcjami, this jest pustym obiektem, ponieważ kod jest zawijany w funkcję przez węzeł, aby utworzyć własny kontekst wykonania dla każdego modułu (pliku skryptu), podczas gdy wewnątrz funkcji, ponieważ są one nazwane z żadnym określonym kontekście realizacji, this jest węzeł GLOBAL obiekt

W node.js ty chcesz dostać

var obj1; 
var obj2; 

function x() { 
    obj1 = this; // GLOBAL 
} 

function y() { 
    obj2 = this; // GLOBAL 
} 

x(); 
y(); 

console.log(obj1 === obj2); // GLOBAL === GLOBAL = true 
console.log(obj1 === this); // GLOBAL === {} = false 

Jeżeli ostatni this jest rzeczywiście pusty obiekt, jak wyjaśniono powyżej


Dla kompletności, to warto zauważyć, że w trybie ścisłym, można uzyskać taki sam wynik w przeglądarce (true, false), jak w węźle, ale to dlatego, że zmienne są po prostu przeciwieństwem tego, co są w węźle

"use strict" 

var obj1; 
var obj2; 

function x() { 
    obj1 = this; // undefined 
} 

function y() { 
    obj2 = this; // undefined 
} 

x(); 
y(); 

console.log(obj1 === obj2); // undefined === undefined = true 
console.log(obj1 === this); // undefined === window = false 

To dlatego, że wartość przekazana jako this do funkcji w trybie ścisłym nie jest zmuszony do życia obiektu (aka "w pudełku").
Dla normalnego funkcjonowania w trybie non-ścisłym, this zawsze jest obiekt, i to zawsze globalny obiekt jeśli nazywa z undefined lub null to-value, to znaczy bez konkretnego kontekstu wykonania.

Nie tylko jest to koszt związany z wydajnością, ale ekspozycja obiektu globalnego w przeglądarkach stanowi zagrożenie bezpieczeństwa, ponieważ obiekt globalny zapewnia dostęp do funkcji, które muszą być ograniczone ze względu na środowisko JavaScript "zabezpieczone".

Zatem dla ścisłego trybu funkcji, określona this nie jest zapakowane w obiekcie, a jeśli nie jest określony, this będzie undefined funkcje wewnątrz, jak przedstawiono powyżej, ale this nadal będzie okno w zasięgu globalnym.

To samo dzieje się w trybie ścisłym w węźle.js, gdzie this w funkcjach nie jest już GLOBAL, ale undefined ipoza tymi funkcjami nadal będzie tym samym pustym obiektem, a końcowym rezultatem będzie nadal true, false, ale wartość this będzie inna w trybie ścisłym w węźle .js również.

+1

Czy ktoś wie * dlaczego * Węzeł używa pustego obiektu jako kontekstu podczas wykonywania modułu? (Nie mogę sobie wyobrazić, że jest to próba ochrony globalnego, ponieważ globalny jest używany jako kontekst, gdy wywoływana jest funkcja). – joeytwiddle

+0

@joeytwiddle - Nie mam pojęcia, zgaduję, że każdy uruchomiony moduł jest po prostu włożony do środka coś takiego jak '(function() {code}());' i ktoś zdecydował, że 'this' będzie pustym obiektem, ponieważ' this' powinno być zawsze zdefiniowane i nie chce, aby był to obiekt globalny . – adeneo

+0

Być może to * jest * próbą ochrony globalnej, ale nadal musieli używać globalnego jako obiektu kontekstu, gdy wywoływana jest funkcja, ponieważ tego wymaga specyfikacja języka. – joeytwiddle

4

Węzeł wyraźnie określa this do eksportu modułu here:

const result = compiledWrapper.apply(this.exports, args); 

apply Co robi jest wyraźnie fixate wartość this (i parametry) - w tym przypadku - to odróżnia ją do this.exports. Na przykład:

(function() { console.log(this.x); }).apply({x:3}); // alerts 3 

Domyślne zachowanie węzła to. Musi jednak wywoływać funkcje wewnątrz obiektu z global - jak nakazuje specyfikacja JS.

+0

Uwaga, to początkowo zaczęło się jako komentarz do odpowiedzi adeneo - zdecydowałem, ponieważ to oznacza, że ​​wysłałem to jako oddzielną odpowiedź i przegrałem jego. Zobacz odpowiedź na więcej _reasoning_ zamiast "tutaj jest kod, który sprawia, że ​​to się dzieje". –

Powiązane problemy