2013-05-05 16 views
8

Mam ten prosty kod:Dlaczego tracę kontekst tego w JavaScript?

var o = { 
    a: 1, 
    b: 2, 
    f1: function() 
    { 
     alert(this.b); 
    } 
} 

var o2 = { 
    a: 11, 
    b: 22, 
    f2: function (j) 
    { 
     j(); 
    } 
} 

Ale działa ten kod:

o2.f2(o.f1) daje w wyniku niezdefiniowanej. (Podczas gdy im spodziewa się „22” jako wynik)

Teraz wiem, że kontekst upadł gdzieś. i stąd Gdybym zmienić kod w o2 do:

f2: function (j) 
    { 
     j.apply(this); 
    } 

To działa oczywiście.

Ale moje pytanie brzmi:

  • W jakim etapie straciłem kontekst?

nie rozumiem: kiedy j() pracuje, tam jest właściwością w obiekcie o2b.

Czego mi brakuje?

jsbin

+9

Kiedy nazywasz to "f()" - metody JavaScript są * "funkcje niezwiązane" * (to znaczy, w przeciwieństwie do metod w innych językach są * nie * powiązane z konkretnym obiektem/instancją) i jest to połączenie -stronę, która określa "to" po wywołaniu. (Oczywiście, zobacz ['Function.bind'] (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind) lub równoważne emulacje.) – user2246674

+0

Tracisz tak szybko podczas przekazywania 'o.f1'. Jeśli wykonasz 'var x = o.f1' i wywołasz' x() ',' f1' nie jest już związany. – Blender

+0

@Blender Wiem o tym. ale dlaczego "to" nie dotyczy "o2"? to jest to, czego nie rozumiem. –

Odpowiedz

6

znalazłem Crockforda miał doskonałą Opis sposobu to działa.Funkcje w JavaScripcie może być wywoływany w 4 wersjach:

  1. Funkcja „” styl
  2. „Metoda” styl
  3. z „Konstruktor” styl
  4. „Wezwanie lub zastosować” styl.

Być może błędnie podaję dokładne nazwy, ale duch jest taki sam. Zdecydowanie powinieneś dostać książkę "JavaScript: dobre części", jeśli jej nie masz.

W każdym razie - na twoje pytanie. Kluczową rzeczą jest to, że wartość, jeśli "to" zależy od stylu, którego używasz.

// function invocation style, 
var f = function() { console.debug(this); } 
f(); // "this" is bound to the global object. 

// "method" invocation style 
var obj = { 
    f: function() { console.debug(this); } 
}; 

obj.f(); // "this" is bound to "obj", the object on which the function was invoked 

// so important bit is : 

var f = obj.f; 
f(); // "this" is global object 
obj.f() // "this" is obj 

W twoim przykładzie tracisz "to" ze względu na sposób, w jaki wywołujesz funkcję.

1

Jeśli zrobisz to tak jak poniżej,

funkcja zostanie wywołana w kontekście o2

var o2 = { 
    a: 11, 
    b: 22, 
    f2: function (j){ 
     this.temp = j; 
     this.temp(); 
    } 
}; 

również te będą działać zbyt:

f2: function (j){ 
     j.apply(this); 
} 

f2: function (j){ 
     j.apply(o2); 
} 

W przeciwnym razie nazywasz to po prostu lik e zwykła funkcja poza kontekstem.

J to wyrwane z kontekstu i nie ma skomplikowanych zamknięć na niej (co nie jest twoim zamiarem), więc za co „to” praca w nim trzeba zakresu. Ten zakres w twoim pytaniu dla j jest oknem, które nie ma w nim "b", więc dostajesz "niezdefiniowane".

+0

ładna sztuczka .. + 1. –

+0

tak, użycie "" tego "jest odpowiedzią – Cherniv

0

Zaznacz to testy:

o.f1(); // alerts 2 

var f3 = o.f1; // (*) 

f3(); // alerts undefined 

o2.f2(f3); // alerts undefined 

f3.apply(o2); // alerts 22 

Zdaję sobie sprawę, że kiedy przekazać funkcję jako parametr kontekst jest stracone w ten sam sposób to utracone w (*) wskazał w kodzie powyżej.

Co dzieje jest j = arguments[0] = o.f1 iw tym momencie tracisz kontekst.

Kiedy przechodzi do funkcji jako parametr jesteś tylko przejazdem odniesienia w pamięci do tej funkcji. Bez wiązania kontekstu nie powiedzie się proste wywołanie j(). Dlatego musisz użyć apply lub sztuczki this pokazanej przez Ihsana.

Powiązane problemy