2010-02-16 10 views
104

Mój kolega użył "nowej funkcji()" z małą literą "f" do zdefiniowania nowych obiektów w JavaScript. Wydaje się, że działa dobrze we wszystkich głównych przeglądarkach i wydaje się również dość skuteczny w ukrywaniu zmiennych prywatnych. Oto przykład:`nowa funkcja()` z małą literą "f" w JavaScript

var someObj = new function() { 
     var inner = 'some value'; 
     this.foo = 'blah'; 

     this.get_inner = function() { 
      return inner; 
     }; 

     this.set_inner = function (s) { 
      inner = s; 
     }; 
    }; 

Gdy tylko użyto "this", staje się ona własnością publiczną someObj. Więc niektóreObj.foo, someObj.get_inner() i someObj.set_inner() są dostępne publicznie. Ponadto, set_inner() i get_inner() są uprzywilejowanymi metodami, dzięki czemu mają dostęp do "wewnętrznych" poprzez zamknięcia.

Jednak nie widziałem żadnego odniesienia do tej techniki w dowolnym miejscu. Nawet Douglasa Crockforda za JSLint narzeka na niego:

  • dziwną konstrukcję. Usuń „nowe”

Używamy tej techniki w produkcji i wydaje się działać dobrze, ale jestem nieco zaniepokojeni, bo to nie jest udokumentowane w dowolnym miejscu. Czy ktoś wie, czy jest to ważna technika?

+5

Preferuję twój konstrukt nad IIFE ("Natychmiastowa funkcja"). 1: Nie potrzebujesz wyraźnego obiektu "instancja", to jest dokładnie to, co "to" w JavaScript. 2: Nie musisz niczego zwracać, co oznacza, że ​​nie musisz o tym pamiętać. Nawet autor zaakceptowanej odpowiedzi zapomniał najpierw zwrócić obiekt instancji! Ludzie zwykle wolą używać IIFE, jeśli nienawidzą nowych i to z nie bez powodu - jeśli masz funkcję obsługującą wydarzenie DOM, "this" będzie odnosić się do elementu, który wystrzelił zdarzenie, a nie twojego obiektu, ale możesz po prostu mieć Zamiast tego należy użyć instancji var. –

+1

Dlaczego ważne jest, aby pytanie określało "małe litery f"? – ClearCloud8

+7

Ponieważ w Javascript istnieje również funkcja "Funkcja" (z dużą literą F), która jest inna: __Function__ to funkcja konstruktora, która może tworzyć nowe obiekty funkcji, podczas gdy __funkcja__ jest słowem kluczowym. –

Odpowiedz

63

Widziałem już tę technikę, jest ona ważna, używasz wyrażenia funkcji tak, jakby była to Constructor Function.

Ale IMHO, można osiągnąć to samo z funkcją auto-ekspresji powołując się, ja naprawdę nie widzę sensu pomocą operatora new w ten sposób:

var someObj = (function() { 
    var instance = {}, 
     inner = 'some value'; 

    instance.foo = 'blah'; 

    instance.get_inner = function() { 
     return inner; 
    }; 

    instance.set_inner = function (s) { 
     inner = s; 
    }; 

    return instance; 
})(); 

Celem operatora new to tworzenie nowych instancji obiektów, konfigurowanie wewnętrznej właściwości , możesz zobaczyć, jak jest ona wykonywana przez wewnętrzną właściwość [Construct].

Powyższy kod da wynik równoważny.

+1

Specyfikacja ECMAScript 262 w rozdziale 13 wyjaśnia to nieco bardziej formalnie. Coś w stylu 'function foo() {}' zwraca wynik utworzenia obiektu "Function" [prawdopodobnie z nową funkcją()]. To cukier składniowy. –

+3

Myślę, że na końcu brakuje "instancji zwrotu"; W przeciwnym razie 'someObj' będzie po prostu' undefined'.:-) –

+0

@Matthew: Tak, przegapiłem oświadczenie 'return', dzięki. – CMS

15

Kod jest tylko podobny do mniej dziwacznym konstruktem

function Foo() { 
    var inner = 'some value'; 
    this.foo = 'blah'; 

    ... 
}; 
var someObj = new Foo; 
+9

Nie jest to po prostu podobne, robi dokładnie to samo ... z jedynym wyjątkiem, że nie będzie w stanie ponownie użyć Foo do stworzenia kolejnego obiektu. – kikito

+3

Wersja OP może być ponownie wykorzystana przez ** new someObj.constructor **. Tutaj konstruktor jest jawnie dodawany do przestrzeni nazw; odpowiedni styl zależy od zamierzonego celu funkcji. Ponadto ten styl - choć z pewnością jest standardem - pozwala komuś wypełnić globalną przestrzeń nazw, jeśli zapomni ** nowego ** przed ** Foo **. –

+0

@kikito co masz na myśli, to nie pozwala na ponowne używanie Foo do tworzenia kolejnego obiektu? var newObj = new Foo() powinno tworzyć nowe wystąpienie. –

12

celu wyjaśnienia niektórych aspektów i dokonania Douglasa Crockforda za JSLint nie narzekać kodzie oto kilka przykładów instancji:

1. o = new Object(); // normal call of a constructor 

2. o = new Object; // accepted call of a constructor 

3. var someObj = new (function() { 
    var inner = 'some value'; 
    this.foo = 'blah'; 

    this.get_inner = function() { 
     return inner; 
    }; 

    this.set_inner = function (s) { 
     inner = s; 
    }; 
})(); // normal call of a constructor 

4. var someObj = new (function() { 
    var inner = 'some value'; 
    this.foo = 'blah'; 

    this.get_inner = function() { 
     return inner; 
    }; 

    this.set_inner = function (s) { 
     inner = s; 
    }; 
}); // accepted call of a constructor 

W przykładzie 3. wyrażenie w (...) jako wartość jest funkcją/konstruktorem. Wygląda to tak: new (function() {...})(). Więc jeśli pominiemy nawiasy kończące, jak w przykładzie 2, wyrażenie jest nadal poprawnym wywołaniem konstruktora i wygląda jak przykład 4.

JSLint Douglasa Crockforda "myśli", że chciałbyś przypisać funkcję do jakiejś Obj, a nie do jej instancji. I w końcu to tylko ostrzeżenie, a nie błąd.