2010-10-26 12 views
8

chcę zrobić to w javascript:Odnosząc się do "tego" w rodzica zamknięcia w javascript

function Z(f) 
{ 
    f(); 
} 

function A() 
{ 
    this.b = function() 
    { 
    Z(function() { this.c() }); 
    } 

    this.c = function() 
    { 
    alert('hello world!'); 
    } 
} 

var foo = new A(); 
foo.b(); 

Może to być osiągnięte w ten sposób:

function Z(f) 
{ 
    f(); 
} 

function A() 
{ 
    var self = this; 
    this.b = function() 
    { 
    Z(function() { self.c() }); 
    } 

    this.c = function() 
    { 
    alert('hello world!'); 
    } 
} 

var foo = new A(); 
foo.b(); 

jest jakiś lepszy sposób?

Odpowiedz

6

Utrzymanie odniesienie do dominującej (jak masz) jest dobrym podejściem, jednakże dla konkretnego przykładu nie ma potrzeby dla anonimowego owijki, można przekazać funkcję bezpośrednio, jak to:

var self = this; 
this.b = function() 
{ 
    Z(self.c); 
} 

You can test it out here, a bez tej owijki tam rzeczywiście nie ma potrzeby zmiennej self, można po prostu użyć this bezpośrednio, jak to:

this.b = function() 
{ 
    Z(this.c); 
} 

You can test that version here.


Ponieważ nie wydaje się być pewne niejasności w komentarzach poniżej, powyższy kod utrzymuje thisna pytanie, jeśli chcesz utrzymać this/kontekst wewnątrz zwrotnego także użyć .call()like this:

this.b = function() 
{ 
    Z.call(this, this.c); 
} 

I Z:

function Z(f) 
{ 
    f.call(this); 
} 

You can test it here.

+0

prawo, w tym prostym przykładzie, nie ma powodu do owinięcia. Nie powinno być trudno wymyślić przykład, w którym jest to konieczne. (Zmiana parametrów itp.) Jeśli nie owijasz, zakładam, że zamknięcie zostało zakończone, jak można by się spodziewać? –

+2

bez anonimowego opakowania, 'c' jest wywoływane z niepoprawnym referencją' this'. – Lee

+0

@ Jonathan - Tak, słusznie, w takim przypadku chciałbyś przekazać zmienną w taki sposób, jakbyś miał "ja", który daje ci dostęp do tego, co jest w zamknięciu. –

1

Istnieje wzorzec, który jest często nazywany "Delegatem", który rozwiązuje ten problem.

w JavaScript, nie-zbyt fantazyjne realizacja może wyglądać mniej więcej tak:

/** class Delegate **/ 
var Delegate = function(thisRef, funcRef, argsArray) { 
    this.thisRef=thisRef; 
    this.funcRef=funcRef; 
    this.argsArray=argsArray; 
} 
Delegate.prototype.invoke = function() { 
    this.funcRef.apply(this.thisRef, this.argsArray); 
} 
/** static function Delegate.create - convenience function **/ 
Delegate.create = function(thisRef, funcRef, argsArray) { 
    var d = new Delegate(thisRef, funcRef, argsArray); 
    return function() { d.invoke(); } 
} 

W przykładzie będzie go używać tak:

this.b = function() { 
    Z(Delegate.create(this, this.c)); 
} 

można również napisać funkcje którzy oczekują na Delegata:

function Z(d) { 
    d.invoke(); 
} 

następnie, w A, twój impl od b staje:

this.b = function() { 
    var d = new Delegate(this, this.c); 

    Z(d); 
    SomeOtherFunc(d); 
} 

Delegate tylko zapewnia prosty i spójny sposób enkapsulacji odniesienie this (co masz nazwie self), wewnątrz instancji obiektu, które mogą być uregulowane jak każdy inny instancji obiektu. Jest bardziej czytelny i nie musi zanieczyszczać zakresu funkcji zbytecznymi zmiennymi, takimi jak self. Mądrzejsza implementacja delegata może mieć własne metody i inny powiązany stan. Możliwe jest również zbudowanie delegata w taki sposób, aby pomógł zminimalizować niektóre problemy związane z zarządzaniem pamięcią (choć kod, który tu pokazałem, zdecydowanie nie jest tego przykładem).

+0

Nie sądzę, że to działa: 'Z (function() {Delegate.create (this, c)});'. Bez opakowania nie ma potrzeby "własnego" i nie ma powodu dla Delegata, ponieważ krótsze jest pisanie 'Z (this.c);'. –

+0

@ Jonathan - dodano dodatkowe opakowanie, którego nie ma w moim przykładzie. to po prostu 'Z (Delegate.create (this, c))'; Rozszerzyłem nieco przykład Delegata, aby był bardziej elastyczny i wyraźniejszy, co się dzieje. – Lee

+0

@ Jonathan - 'Z (this.c)' zadziała, o ile nie dbasz o to, który obiekt 'this' odwołuje się podczas działania wewnątrz' c'. Pokazany kod nie używa 'this' z wewnątrz' c', więc nie będzie stwarzał żadnych problemów. Jeśli wyewidencjonujesz (ta drobna modyfikacja przykładu @ Nicka) [http://jsfiddle.net/UQpnX/], zobaczysz potencjalny problem, który jest rozwiązany przez anonimowe opakowanie, w twoim oryginalnym przykładzie - lub z bardziej formalna konstrukcja, taka jak Delegat. Każda z nich jest w porządku. – Lee

1

Można alternatywnie użyć

this.b = function() 
{ 
    Z((function() { this.c() }).apply(this)); 
} 
Powiązane problemy