W innym pytaniu użytkownik wskazał, że new
użycie słowa kluczowego jest niebezpieczne, i zaproponował rozwiązanie do tworzenia obiektów, które nie było używane new
. Nie wierzyłem, że to prawda, głównie dlatego, że użyłem Prototype, Scriptaculous i innych doskonałych bibliotek JavaScript i wszyscy używali tego new
słowa kluczowego.
Mimo to wczoraj oglądałem przemówienie Douglasa Crockforda w teatrze YUI i powiedział dokładnie to samo, że nie używał new
już tego słowa kluczowego w swoim kodzie ( Crockford w JavaScript - Akt III: Funkcja ostateczna - 50:23 minut ).
Czy użycie new
słowa kluczowego jest „złe” ? Jakie są zalety i wady korzystania z niego?
javascript
Pablo Fernandez
źródło
źródło
new
. Ale kiedy spojrzysz na bibliotekę YUI. Musisz używaćnew
wszędzie. Takich jakvar myDataSource = new Y.DataSource.IO({source:"./myScript.php"});
.init
metodę, jeśli używasz tegoObject.create
podejścia i wywołać to później. Znacznie łatwiejszy w użyciu,new
który robi oba, ustawia łańcuch prototypów i wywołuje kod inicjujący.new
nie jest niebezpieczne. Pominięcienew
jest niebezpieczne, a zatem złe . Ale w ES5 możesz użyć trybu ścisłego , który chroni cię przed tym niebezpieczeństwem i wieloma innymi.Odpowiedzi:
Crockford zrobił wiele, aby spopularyzować dobre techniki JavaScript. Jego opinie na temat kluczowych elementów języka wywołały wiele przydatnych dyskusji. To powiedziawszy, jest zdecydowanie zbyt wielu ludzi, którzy traktują każde głoszenie „złego” lub „szkodliwego” jako ewangelii, odmawiając spojrzenia poza opinię jednego człowieka. Czasami może to być trochę frustrujące.
Korzystanie z funkcji
new
słowa kluczowego ma kilka zalet w porównaniu z budowaniem każdego obiektu od zera:prototype
i używaćnew
do wybijania nowych obiektów. Jest to nie tylko szybsze (nie wymaga kodu dla każdej metody w prototypie), ale również pozwala uniknąć balonowania każdego obiektu z osobnymi właściwościami dla każdej metody. W przypadku wolniejszych maszyn (a zwłaszcza wolniejszych interpreterów JS), gdy tworzonych jest wiele obiektów, może to oznaczać znaczne oszczędności czasu i pamięci.I tak,
new
ma jedną istotną wadę, dobrze opisaną innymi odpowiedziami: jeśli zapomnisz go użyć, Twój kod złamie się bez ostrzeżenia. Na szczęście tę wadę można łatwo złagodzić - wystarczy dodać trochę kodu do samej funkcji:Teraz możesz korzystać z zalet,
new
nie martwiąc się o problemy spowodowane przypadkowym niewłaściwym użyciem. Możesz nawet dodać twierdzenie do czeku, jeśli przeszkadza ci myśl o uszkodzonym kodzie cicho działającym. Lub, jak niektórzy komentowali, użyj zaznaczenia, aby wprowadzić wyjątek czasu wykonywania:(Pamiętaj, że ten fragment kodu pozwala uniknąć zakodowania na stałe nazwy funkcji konstruktora, ponieważ w przeciwieństwie do poprzedniego przykładu nie ma potrzeby rzeczywistego tworzenia instancji obiektu - dlatego można go skopiować do każdej funkcji docelowej bez modyfikacji.)
John Resig szczegółowo omawia tę technikę w swoim prostym poście „Tworzenie klasy” , a także domyślnie włącza sposoby budowania tego zachowania w „klasach”. Na pewno warto przeczytać ... jak jego zbliżający się książka Tajemnice JavaScript Ninja , który odnajduje ukryte złoto w tej i wielu innych „szkodliwe” cech języka JavaScript (the rozdział na
with
szczególnie oświecania dla tych z nas, którzy początkowo odrzucona ta bardzo złośliwa funkcja jako chwyt).źródło
new
lub użyj funkcji otoki, aby zapamiętać ją dla Ciebie. I podejrzewam , że jeśli jesteś w miejscu, gdzie ma to znaczenie, już wyczerpane inne optymalizacje, takie jak memoization, dzięki czemu tworzenie połączeń będą zlokalizowane w każdym razie ...arguments.callee
do sprawdzania, czy zostałeś wezwany,new
może nie być tak dobre, ponieważarguments.callee
nie jest dostępne w trybie ścisłym. Lepiej użyć nazwy funkcji.new
ponieważ możesz zapomnieć o napisaniu go w kodzie, jest tak samo niedorzeczne jak mój przykład.Właśnie przeczytałem niektóre części jego książki Crockfords „JavaScript: The Good Parts”. Mam wrażenie, że uważa wszystko, co kiedykolwiek go ugryzło, za szkodliwe:
O przełączniku spadają:
Informacje o ++ i -
O nowym:
Jest ich więcej, ale mam nadzieję, że dostaniesz zdjęcie.
Moja odpowiedź na twoje pytanie: nie, to nie jest szkodliwe. ale jeśli zapomnisz go użyć, możesz mieć problemy. Jeśli rozwijasz się w dobrym środowisku, zauważysz to.
Aktualizacja
Około rok po napisaniu tej odpowiedzi wydano 5. edycję ECMAScript ze wsparciem dla trybu ścisłego . W trybie ścisłym
this
nie jest już związany z obiektem globalnym, ale zundefined
.źródło
JavaScript jest dynamicznym językiem, istnieje mnóstwo sposobów na zepsucie się w miejscu, w którym zatrzyma Cię inny język.
Unikanie podstawowej funkcji językowej, na przykład
new
powodowania bałaganu, przypomina trochę zdejmowanie nowych błyszczących butów przed przejściem przez pole minowe na wypadek, gdyby buty się zabrudziły.Używam konwencji, w której nazwy funkcji zaczynają się od małej litery, a „funkcje”, które są definicjami klas, zaczynają się od dużej litery. Rezultatem jest naprawdę bardzo przekonująca wizualna wskazówka, że „składnia” jest nieprawidłowa: -
Oprócz tego pomagają dobre nawyki nazywania. Po tym, jak wszystkie funkcje działają, dlatego w nazwie powinien znajdować się czasownik, podczas gdy klasy reprezentują obiekty i są rzeczownikami i przymiotnikami bez czasownika.
Interesujące jest to, w jaki sposób kolorystyka składniowa SO zinterpretowała powyższy kod.
źródło
if (! this instanceof MyClass) return new MyClass()
) wolęnew
składnię bez użycia. Dlaczego? Ponieważ funkcje są bardziej ogólne niż funkcje konstruktora . Opuszczenienew
ułatwia zmianę funkcji konstruktora na funkcję zwykłą ... Lub na odwrót. Dodanienew
powoduje, że kod jest bardziej szczegółowy niż powinien. A zatem mniej elastyczny. Porównaj z Javą, gdzie zaleca się zaakceptowaćList
zamiast,ArrayList
aby osoba dzwoniąca mogła wybrać implementację.Jestem początkującym w Javascript, więc może nie mam zbyt dużego doświadczenia w zapewnianiu dobrego punktu widzenia na ten temat. Jednak chcę podzielić się moim poglądem na temat tej „nowej” rzeczy.
Pochodzę ze świata C #, w którym użycie słowa kluczowego „nowy” jest tak naturalne, że dziwnie wygląda dla mnie wzór fabryczny.
Kiedy po raz pierwszy koduję w Javascript, nie zdaję sobie sprawy z tego, że istnieje „nowe” słowo kluczowe i kod podobny do tego we wzorze YUI i nie zajmuje mi to dużo czasu. Nie pamiętam, co powinna robić konkretna linia, patrząc wstecz na napisany przeze mnie kod. Bardziej chaotyczne jest to, że mój umysł nie może tak naprawdę przechodzić między granicami instancji obiektów, kiedy „uruchamiam” na sucho kod.
Następnie znalazłem „nowe” słowo kluczowe, które według mnie „oddziela” rzeczy. Dzięki nowemu słowu kluczowemu tworzy rzeczy. Bez nowego słowa kluczowego wiem, że nie pomylę go z tworzeniem rzeczy, chyba że funkcja, którą wywołuję, daje mi silne wskazówki na ten temat.
Na przykład, gdy
var bar=foo();
nie mam żadnych wskazówek co do tego, jaki pasek mógłby być… Czy to jest wartość zwracana, czy jest to nowo utworzony obiekt? Ale zvar bar = new foo();
pewnością wiem, że pasek jest przedmiotem.źródło
typeof new foo() == "object"
. Tonew
zwraca instancjęfoo
i wiesz, że możesz zadzwonićfoo.bar()
ifoo.bang()
. Można to jednak łatwo złagodzić, używając @return JsDoc Nie dlatego, że jestem zwolennikiem kodu proceduralnego (unikając słowanew
)Innym przypadkiem za nowy jest to, co ja nazywam Puchatek kodowania . Kubuś Puchatek podąża za jego brzuchem. Mówię idź z językiem, którego używasz, a nie przeciwko .
Są szanse, że opiekunowie języka zoptymalizują język pod kątem idiomów, które próbują zachęcić. Jeśli dodadzą nowe słowo kluczowe do języka, prawdopodobnie uważają, że sensowne jest, aby było jasne podczas tworzenia nowej instancji.
Kod napisany zgodnie z intencjami języka będzie zwiększał wydajność z każdym wydaniem. Z czasem kod unikający kluczowych konstrukcji języka będzie cierpiał.
EDYCJA: I to znacznie wykracza poza wydajność. Nie mogę policzyć razy słyszałem (lub mówi) „dlaczego do cholery zrobili , że ?” przy znajdowaniu dziwnie wyglądającego kodu. Często okazuje się, że w momencie pisania kodu istniał jakiś „dobry” powód. Podążanie za Tao języka jest najlepszym ubezpieczeniem za to, że za kilka lat nie wyśmiejesz kodu.
źródło
Napisałem post, jak złagodzić problem wywołania konstruktora bez nowego słowa kluczowego.
Jest to głównie dydaktyczne, ale pokazuje, w jaki sposób można tworzyć konstruktory, które działają z lub bez
new
i nie wymagają dodawania kodu testerathis
w każdym konstruktorze.http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html
Oto sedno techniki:
Oto jak go użyć:
źródło
arguments.callee
jest niesamowite!surrogateConstructor
powinno byćsurrogateCtor
(lub odwrotnie).Uzasadnienie nieużywania nowego słowa kluczowego jest proste:
W ogóle go nie wykorzystując unikniesz pułapki, która przypadkowo go ominie. Wzorzec konstrukcyjny, którego używa YUI, jest przykładem tego, jak można całkowicie uniknąć nowego słowa kluczowego „
Alternatywnie możesz to zrobić:
Ale robiąc to, ryzykujesz, że ktoś zapomni użyć nowego słowa kluczowego, a ten operator będzie fubarem. AFAIK nie ma z tego żadnej korzyści (poza tym, że jesteś do tego przyzwyczajony).
Na koniec dnia: chodzi o obronę. Czy możesz użyć nowego wyciągu? Tak. Czy to czyni twój kod bardziej niebezpiecznym? Tak.
Jeśli kiedykolwiek pisałeś C ++, przypomina to ustawianie wskaźników na NULL po ich usunięciu.
źródło
Myślę, że „nowy” dodaje przejrzystości kodu. A przejrzystość jest warta wszystkiego. Dobrze wiedzieć, że są pułapki, ale unikanie ich poprzez unikanie klarowności nie wydaje mi się właściwą drogą.
źródło
Przypadek 1:
new
nie jest wymagany i należy go unikaćPrzypadek 2:
new
jest wymagany, w przeciwnym razie pojawi się błądźródło
toString()
). We wszystkich innych przypadkach używaj literałów. NieString('asd')
, ale po prostu'asd'
i nieNumber(12)
, ale po prostu12
.Array
:Array(5).fill(0)
jest oczywiście bardziej czytelne niż[undefined, undefined, undefined, undefined, undefined].fill(0)
i(var arr = []).length = 5; arr.fill(0);
new
z konstruktorami dla typów obiektów odpowiadających typom pierwotnym . Dosłowne że sugeruje to nie równoważneArray
wezwanie (TRY0 in …
), a reszta jest błąd składni :) W przeciwnym razie są poprawne, chociaż należy zauważyć, jak dobrze, żeArray(5)
mogą być niejednoznaczne jeśli wziąć pod uwagę niezgodnych implementacje (i dlatego emulowanyArray.prototype.fill(…)
).Oto najkrótsze podsumowanie dwóch najsilniejszych argumentów za i przeciw użyciu
new
operatora:Argumenty przeciw
new
new
operatora mogą mieć katastrofalne skutki, jeśli zostaną niepoprawnie wywołane jako normalne funkcje. W takim przypadku kod funkcji zostanie wykonany w zakresie, w którym funkcja jest wywoływana, zamiast w zakresie obiektu lokalnego, zgodnie z przeznaczeniem. Może to spowodować zastąpienie globalnych zmiennych i właściwości katastrofalnymi konsekwencjami.function Func()
, a następnie wywoływanieFunc.prototype
i dodawanie do niego elementów, aby można było wywoływaćnew Func()
konstrukcję obiektu, wydaje się brzydkie dla niektórych programistów, którzy wolą używać innego stylu dziedziczenia obiektów ze względów architektonicznych i stylistycznych.Więcej informacji na temat tego argumentu można znaleźć w świetnej i zwięzłej książce Douglasa Crockforda Javascript: The Good Parts. W rzeczywistości i tak to sprawdź.
Argument za
new
new
operatora wraz z przypisaniem prototypu jest szybkie.Zobacz post Johna Resiga, aby uzyskać proste wyjaśnienie tej techniki i ogólnie głębsze wyjaśnienie modelu dziedziczenia, który on popiera.
źródło
'use strict';
trybu (lub metody w łączu) # 2 Ma cukier synatyczny w ES6 , jednak zachowanie jest takie samo jak poprzednio.Zgadzam się z Pez i niektórymi tutaj.
Wydaje mi się oczywiste, że „nowy” to samoopisujące tworzenie obiektów, w którym wzorzec YUI, który opisuje Greg Dean, jest całkowicie zaciemniony .
Możliwość, że ktoś mógłby napisać
var bar = foo;
lub gdyvar bar = baz();
baza nie jest metodą tworzenia obiektów, wydaje się znacznie bardziej niebezpieczna.źródło
Myślę, że nowe jest złe, nie dlatego, że jeśli zapomnisz go użyć przez pomyłkę, może to powodować problemy, ale dlatego, że psuje łańcuch dziedziczenia, utrudniając zrozumienie języka.
JavaScript jest zorientowany obiektowo na prototypy. Dlatego każdy obiekt MUSI być utworzony z innego obiektu takiego
var newObj=Object.create(oldObj)
. Tutaj oldObj nazywa się prototypem newObj (stąd „oparty na prototypie”). Oznacza to, że jeśli właściwość nie zostanie znaleziona w newObj , zostanie przeszukana w oldObj . newObj domyślnie będzie zatem pustym obiektem, ale ze względu na swój łańcuch prototypów wydaje się, że ma wszystkie wartości oldObj .Z drugiej strony, jeśli to zrobisz
var newObj=new oldObj()
, prototypem newObj jest oldObj.prototype , co jest niepotrzebnie trudne do zrozumienia.Sztuką jest użycie
Jest w tej funkcji i tylko tutaj należy użyć nowej. Następnie skorzystaj z Object.create () . Metoda rozwiązuje problem prototypu.
źródło
var c = new Car()
to to samo co robienievar c = Object.create(Car.prototype); Car.call(c)