2012-02-16 10 views
10

znalazłem coś bardzo dziwny dzisiaj: W przypadku tworzenia obiektów o funkcji konstruktora i hasła new, ale return zależności od konstruktora, to zachowuje się tak:Używanie „powrót” podczas tworzenia obiektów z „nowych”

  1. Nowo utworzony "obiekt" jest zamiast tego funkcją.
  2. Ta nowa funkcja może być wywołana jak normalne, jednak ...
  3. Jeśli zachować odniesienie do this w funkcji konstruktora, this odniesienia do obiektu, który został prawidłowo utworzony od konstruktora. To jest to, czego oczekiwałeś, że wrócisz z new.

Oto przykład:

function Constructor() { 
    var self = this; 

    this.name = 'instance'; 
    return function() { 
    return self; 
    } 
} 

Więc jeśli instancja to tak: var instance = new Constructor() Poniższa skutkowałoby:

typeof instance //returns "function" 
typeof instance() //returns "object" 
instance()   //returns { name: 'instance' } 

Więc myślę, że mam trzy pytania:

  1. Czy to jest legalne i czy to działa? k między przeglądarkami? To naprawdę niesamowite i myślę, że można go używać na wiele sposobów, ale czy to zachowanie jest niezawodne?
  2. Co dzieje się w tle, które powoduje to zachowanie?
  3. (może być odpowiedzią 2, ale ...) Czy nowy obiekt (ten, do którego odnosi się "to") wewnątrz nowej instancji, tak że jest on samowystarczalny i czy jest prawidłowo czyszczony przez garbage collector?
+0

Błędem jest "zwrócić" wszystko od konstruktora, ostatnio słyszałem. –

Odpowiedz

7
  1. Tak, podczas gdy konstruktor domyślnie zwraca nowy obiekt budowany (który jest określany przez this) można przesłonić tej wartości zwracanej tak długo, jak zwrócić obiekt. Ponieważ funkcja jest obiektem, możesz ją zwrócić tak jak w twoim przykładzie. Nowo utworzony obiekt to sama funkcja, ale zwrócona funkcja odwołuje się do nowo utworzonego obiektu w jego zakresie zmiennych.

  2. See # 1

  3. To dlatego, że funkcja tworzy zamknięcie, więc nadal odwoływać się do zmiennej self, co dzieje się odwoływać rzeczywisty obiekt w trakcie budowy. Więc nie powiedziałbym, że jest to "wewnątrz" czegokolwiek, ale raczej jest po prostu częścią zakresu zmiennego funkcji.

Należy zrozumieć, że twoja funkcja nie różni się od żadnej innej funkcji. Podobnie jak gdybyś zwrócił tablicę, miałbyś zwykłą tablicę, która mogłaby odnosić się do nowego obiektu.

function Constructor() { 

    this.name = 'instance'; 
    return [ this ]; // Instead return an Array that references the new object 
} 
+0

Rozumiem! Więc zmienna "instancja" w moim przykładzie to * zamknięcie *, a nie normalna funkcja? A to zamknięcie zawiera zarówno zwróconą funkcję AND instancjonowany obiekt, do którego można uzyskać dostęp za pomocą "tego"? –

+2

@KevinMcTigue: Cóż, wszystkie funkcje są zamykane. Jest to po prostu częścią wewnętrznej implementacji funkcji w JavaScript. To, co sprawia, że ​​funkcja jest zamknięta, to stałe odniesienie do pierwotnego zakresu zmiennych, w którym zostało utworzone. Więc właśnie zwracasz zwykłą, starą funkcję, która zachowuje się właściwie jak każda inna funkcja, ponieważ nie traci z pola widzenia swojego zakresu zmiennego * (który zawiera zmienną 'self', która odwołuje się do twojego nowego obiektu) *. –

2

Cóż, to naprawdę dobre pytanie, a jak łatwo się domyślić, niełatwo odpowiedzieć.

Mówiąc prościej:
1) Tak i tak; jest to jedna z niesamowitych funkcji, których nie można znaleźć w "tradycyjnych" językach programowania.
2) proszę przeczytać o zamknięć (linki poniżej)
3) Tak (proszę czytaj więcej)

należy przeczytać więcej o Javascript Zamknięcia: http://jibbering.com/faq/notes/closures/
http://www.javascriptkit.com/javatutors/closures.shtml (tu masz kilka dobrych przykładów roboczy)

, a bardziej szczegółowo, pasożytniczego modelu dziedziczenia:
http://blog.higher-order.net/2008/02/21/javascript-parasitic-inheritance-power-constructors-and-instanceof/

mam nadzieję, że to pomoże

+0

Dzięki za linki. Drugi jest bardzo interesujący. Nauczyłem się nowego terminu dzisiaj: Power Constructor –

1

to jest to, co nazywamy closure

co robi jest stworzenie autonomicznego środowiska kodu (powszechnie znany jako obiekt)

typeof instance //returns "function" - since it's not "fired" or called. just returns the function declaration (correct me if i'm wrong) 
typeof instance() //returns "object" - it returns an object since you called it 
instance()   //returns an object also - you called it, but you didn't store it 

przykład obiekt zbudowany z wykorzystaniem zamknięcie:

function Constructor() { 
    var privateProperty = 'private'; 
    var privateMethod = function(){ 
     alert('called from public method'); 
    }; 

    //return only what's to be seen in public 
    return { 
     publicProperty: 'im public', 
     publicMethod: function(){ 
      alert('called from public method'); 
     } 
     getter: privateMethod //assign to call the private method 
    } 
} 

var myObj = Constructor(); 
var pubProp = myObj.publicProperty; // pubProp = 'im public' 
myObj.publicMethod()    //alert: 'called from public method'; 
myObj.getter()      //alert: 'called from public method'; 

//cannot access since "private": 
myObj.privateProperty 
myObj.privateMethod 
+1

_ "to, co robi, tworzy niezależne środowisko kodu (powszechnie znane jako obiekt)" _ - Powszechnie znane jako "zamknięcie". To nie jest "obiekt", przynajmniej nie w tym sensie, że jest obiektem JS. Ponadto, jeśli twoja funkcja jawnie zwraca obiekt, nie jest dobrą praktyką wywoływanie go za pomocą 'new', ponieważ jest to mylące - jeśli użyjesz' new', możesz oczekiwać, że wynik będzie instancją 'Constructor'. – nnnnnn

+0

Zgodnie ze stroną MDN na temat zamknięć: * "Zamknięcie to szczególny rodzaj obiektu, który łączy dwie rzeczy: funkcję i środowisko, w którym ta funkcja została utworzona." * –

+1

@nnnnnn Po prostu wyjaśniłem w prostych słowach. chociaż nie jest to anobject, to często używa go do emulacji obiektu (posiadającego prywatne i publiczne właściwości). co do "nowego" ... nie wiedziałem o tym. – Joseph

Powiązane problemy