Czy "nowe" słowo kluczowe JavaScript jest uważane za szkodliwe?
W innym pytaniu użytkownik wskazał, że słowo kluczowe new
jest niebezpieczne w użyciu i zaproponował rozwiązanie do tworzenia obiektów, które nie używają new
. Nie wierzyłem, że to prawda, głównie dlatego, że używałem Prototype, Scriptaculous i innych doskonałych bibliotek JavaScript, a każdy z nich używał słowa kluczowego new
.
new
(Crockford on JavaScript-Act III: Function The Ultimate-50: 23 minut).
Czy używanie słowa kluczowego new
jest "złe"? Jakie są zalety i wady korzystania z niego?
12 answers
Crockford zrobił wiele, aby popularyzować dobre techniki JavaScript. Jego opinia na temat kluczowych elementów języka wywołała wiele użytecznych dyskusji. To powiedziawszy, jest zbyt wielu ludzi, którzy traktują każde głoszenie "złego" lub "szkodliwego" jako Ewangelię, odmawiając spojrzenia poza zdanie jednego człowieka. Czasami może to być trochę frustrujące.
Wykorzystanie funkcjonalności dostarczonej przez słowo kluczowe new
ma kilka zalet w stosunku do budowania każdego obiektu z scratch:
- dziedziczenie prototypu . Chociaż często patrzył na mieszankę podejrzeń i szyderstw przez tych, którzy przyzwyczajeni są do języków oo opartych na klasach, natywna technika dziedziczenia JavaScript jest prostym i zaskakująco skutecznym sposobem ponownego użycia kodu. A nowe słowo kluczowe jest kanonicznym (i dostępnym tylko na wielu platformach) sposobem jego użycia.
- wydajność. Jest to efekt uboczny #1: Jeśli chcę dodać 10 metod do każdego tworzonego obiektu, mogę wystarczy napisać funkcję tworzenia, która ręcznie przypisuje każdą metodę do każdego nowego obiektu... Mogę też przypisać je do funkcji tworzenia
prototype
i użyćnew
, aby wytłoczyć nowe obiekty. Nie tylko jest to szybsze (nie wymaga kodu dla każdej metody na prototypie), ale pozwala uniknąć balonowania każdego obiektu z osobnymi właściwościami dla każdej metody. Na wolniejszych maszynach (a zwłaszcza wolniejszych interpretatorach JS), gdy powstaje wiele obiektów, może to oznaczać znaczną oszczędność czasu i pamięć.
I tak, new
ma jedną zasadniczą wadę, umiejętnie opisaną przez inne odpowiedzi: jeśli zapomnisz jej użyć, twój kod pęknie bez ostrzeżenia. Na szczęście ta wada jest łatwo zniwelowana - wystarczy dodać trochę kodu do samej funkcji:
function foo()
{
// if user accidentally omits the new keyword, this will
// silently correct the problem...
if ( !(this instanceof foo) )
return new foo();
// constructor logic follows...
}
Teraz możesz mieć zalety new
bez martwienia się o problemy spowodowane przypadkowym niewłaściwym użyciem. Możesz nawet dodać twierdzenie do sprawdzenia, czy myśl o złamanym kodzie cicho działającym przeszkadza ty. Lub, jak skomentowali niektórzy , użyj czeku, aby wprowadzić wyjątek runtime:
if ( !(this instanceof arguments.callee) )
throw new Error("Constructor called as a function");
(zauważ, że ten fragment jest w stanie uniknąć kodowania nazwy funkcji konstruktora, ponieważ w przeciwieństwie do poprzedniego przykładu nie ma potrzeby tworzenia instancji obiektu-dlatego może być skopiowany do każdej funkcji docelowej bez modyfikacji.)
[[8]}John Resig szczegółowo omawia tę technikę w swoim poście prosta instancja "klasy" , a także zawiera środki budowanie tego zachowania w swoich "klasach" domyślnie. Zdecydowanie warto przeczytać... podobnie jak jego kolejna książka, Secrets of the JavaScript Ninja , która znajduje ukryte złoto w tym i wielu innych "szkodliwych" cechach języka JavaScript (rozdział {36]} on {[7] } jest szczególnie pouczający dla tych z nas, którzy początkowo odrzucili tę bardzo złośliwą funkcję jako sztuczkę).Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:25
Właśnie przeczytałem kilka 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 switch fall through:
Nigdy nie pozwalam, aby sprawy switch upadły do następnej sprawy. Kiedyś znalazłem błąd w moim kodzie spowodowany przez / align = "left" / po energicznym przemówieniu o tym, dlaczego Upadek był czasem przydatne. (strona 97, ISBN 978-0-596-51774-8)
O ++ I --
The ++ (increment) and -- (decrement) operatorzy byli znani z przyczynić się do złego kodu poprzez zachęcanie ekscesywne oszustwo. Są drugie tylko do wadliwej architektury w włączanie wirusów i innych zabezpieczeń menaces. (strona 122)
O Nowym:
Jest ich więcej, ale mam nadzieję, że zrozumiesz. Moja odpowiedź na twoje pytanie: nie, to nie jest szkodliwe. ale jeśli zapomnisz go użyć, kiedy powinieneś, możesz mieć pewne problemy. Jeśli rozwijasz w dobrym otoczeniu można to zauważyć.Jeśli zapomnisz dołączyć Nowy przedrostek przy wywołaniu konstruktora funkcji, wtedy to nie będzie bound to nowy obiekt. Niestety, to będzie związany z obiektem globalnym, więc zamiast powiększać swój nowy obiekt, będziesz trzepać globalnie zmienne. To jest naprawdę złe. Tam nie ma ostrzeżenia kompilacji i nie ma ostrzeżenie o uruchomieniu. (strona 49)
Update
Około rok po napisaniu tej odpowiedzi ukazała się piąta edycja ECMAScript, z obsługą strict mode. W trybie strict, {[0] } nie jest już związane z obiektem globalnym, ale z undefined
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-25 16:59:40
Javascript jako dynamiczny język istnieje milion sposobów na bałagan tam, gdzie inny język by cię zatrzymał.
Unikanie podstawowych funkcji językowych, takich jak new
na podstawie tego, że możesz zepsuć, jest trochę jak zdejmowanie nowych, błyszczących butów przed pójściem przez pole minowe, na wypadek, gdyby buty były zabłocone.
Używam konwencji, w której nazwy funkcji zaczynają się od małej litery, A 'funkcje', które są w rzeczywistości definicjami klas, zaczynają się od wielkiej litery list. Wynik jest naprawdę dość przekonującą wizualną wskazówką, że 'składnia' jest zła: - {]}
var o = MyClass(); // this is clearly wrong.
Poza tym dobre nawyki nazewnicze pomagają. W końcu wszystkie funkcje robią rzeczy i dlatego w jego nazwie powinien być czasownik, podczas gdy klasy reprezentują przedmioty i są rzeczownikami i przymiotnikami bez czasownika.
var o = chair() // Executing chair is daft.
var o = createChair() // makes sense.
Ciekawe jak kolorowanie składni so zinterpretowało powyższy kod.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-30 21:03:52
Jestem nowicjuszem w Javascript, więc może nie jestem zbyt doświadczony w dostarczaniu dobrego punktu widzenia. Chcę jednak podzielić się moim poglądem na ten" nowy " temat.
Pochodzę ze świata C#, gdzie użycie słowa kluczowego " new " jest tak naturalne, że to fabryczny wzorzec projektowy wygląda dla mnie dziwnie.
Kiedy po raz pierwszy koduję w Javascript, nie zdaję sobie sprawy, że istnieje" nowe " słowo kluczowe i Kod jak ten we wzorze YUI i nie zajmuje mi dużo czasu, aby wpaść w katastrofę. I lose śledzenie tego, co dana linia ma robić, patrząc wstecz na kod, który napisałem. Bardziej chaotyczne jest to, że mój umysł nie może tak naprawdę przejść między granicami instancji obiektów, kiedy jestem "suchy" kod.
Potem znalazłem" nowe " słowo kluczowe, które dla 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ę, da mi silne wskazówki.
Na przykład, z var bar=foo();
nie mam żadnych wskazówek, jaki może być bar.... Jest to wartość zwracana czy nowo utworzony obiekt? Ale z var bar = new foo();
wiem na pewno, że bar jest obiektem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-16 13:09:55
Kolejny przypadek dla nowy jest to, co nazywam Puchatek . Kubuś Puchatek podąża za brzuchem. Mówię: idź z językiem, którego używasz, a nie przeciwko temu.
Są szanse, że opiekunowie języka zoptymalizują język pod kątem idiomów, do których starają się zachęcać. Jeśli dodają nowe słowo kluczowe do języka, prawdopodobnie uważają, że ma to sens, aby być jasnym podczas tworzenia nowej instancji.
Kod napisany zgodnie z intencjami języka zwiększy wydajność z każdym wydaniem. A kod unikający kluczowych konstrukcji języka będzie cierpieć z czasem.
EDIT: a to znacznie wykracza poza wydajność. Nie mogę zliczyć razy, które słyszałem (lub powiedziałem) "dlaczego oni to zrobili ?"podczas znajdowania 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 Twój kod nie wyśmiewa niektórych za wiele lat.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-17 07:11:37
Napisałem post o tym, jak złagodzić problem wywołania konstruktora bez nowego słowa kluczowego.
Jest w większości dydaktyczny, ale pokazuje, jak można tworzyć konstruktory, które działają z new
lub bez new
i nie wymaga dodawania kodu kotła do testowania this
w każdym konstruktorze.
Http://js-bits.blogspot.com/2010/08/constructors-without-using-new.html
Oto istota techniki:
/**
* Wraps the passed in constructor so it works with
* or without the new keyword
* @param {Function} realCtor The constructor function.
* Note that this is going to be wrapped
* and should not be used directly
*/
function ctor(realCtor){
// This is going to be the actual constructor
return function wrapperCtor(){
var obj; // object that will be created
if (this instanceof wrapperCtor) {
// Called with new
obj = this;
} else {
// Called without new. Create an empty object of the
// correct type without running that constructor
surrogateCtor.prototype = wrapperCtor.prototype;
obj = new surrogateCtor();
}
// Call the real constructor function
realCtor.apply(obj, arguments);
return obj;
}
function surrogateCtor() {}
}
Oto jak go używać:
// Create our point constructor
Point = ctor(function(x,y){
this.x = x;
this.y = y;
});
// This is good
var pt = new Point(20,30);
// This is OK also
var pt2 = Point(20,30);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-24 18:28:17
Uzasadnienie braku użycia nowego słowa kluczowego jest proste:
Nie używając go w ogóle, unikasz pułapki, która przychodzi z przypadkowym pominięciem go. Wzór konstrukcyjny, którego używa YUI, jest przykładem tego, jak można całkowicie uniknąć nowego słowa kluczowego "var foo = function () {
var pub= { };
return pub;
}
var bar = foo();
Alternatywnie możesz TAK:
function foo() { }
var bar = new foo();
Ale w ten sposób ryzykujesz, że ktoś zapomni użyć new, a Ten operator będzie cały fubar. AFAIK nie ma korzyści z robienia tego (poza tym, że jesteś do tego przyzwyczajony).
/ Align = "left" / możesz użyć nowego Oświadczenia? Tak. Czy to czyni Twój kod bardziej niebezpiecznym? Tak.Jeśli kiedykolwiek pisałeś C++, jest to podobne do ustawiania wskaźników NA NULL po ich usunięciu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-16 13:11:09
Myślę, że "nowy" dodaje jasności do kodu. A jasność jest warta wszystkiego. Dobrze wiedzieć, że są pułapki, ale unikanie ich przez unikanie jasności nie wydaje mi się sposobem.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-20 16:12:11
Przypadek 1: new
nie jest wymagany i należy go unikać
var str = new String('asd'); // type: object
var str = String('asd'); // type: string
var num = new Number(12); // type: object
var num = Number(12); // type: number
Case 2: new
jest wymagane, w przeciwnym razie otrzymasz błąd
new Date().getFullYear(); // correct, returns the current year, i.e. 2010
Date().getFullYear(); // invalid, returns an error
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-26 17:27:58
Oto krótkie podsumowanie dwóch najsilniejszych argumentów za i przeciw używaniu operatora new
:
Argument przeciw new
- funkcje przeznaczone do
utworzone jako obiekty przy użyciu
new
operator może mieć katastrofalne efekty, jeśli są niepoprawne wywoływane jako normalne funkcje. A kod funkcji w takim przypadku będzie być wykonywane w zakresie, w którym funkcja jest wywoływana, zamiast w zakres obiektu lokalnego jako zamierzony. Może to spowodować global zmienne i właściwości do uzyskania nadpisane katastrofą konsekwencje. - wreszcie pisanie
function Func()
, a następnie wywołanieFunc.prototype
i dodawanie do niego rzeczy, aby can callnew Func()
to construct Twój obiekt wydaje się brzydki dla niektórych programistów, którzy woleliby używać inny styl dziedziczenia obiektów dla architektury i stylistyki powody.
Aby dowiedzieć się więcej na ten temat, sprawdź świetną i zwięzłą książkę Douglasa Crockforda Javascript: dobre części. Zobacz też w każdym razie.
Argument na rzecz new
- używając operatora
new
wraz z zadanie prototypowe jest szybkie. - to coś o przypadkowym uruchamianie funkcji konstruktora kod w globalnej przestrzeni nazw może łatwo zapobiegać, jeśli zawsze Dołącz trochę kodu do swojego funkcje konstruktora do sprawdzenia zobacz, czy są powoływani prawidłowo, a w przypadkach, gdy nie są, Obsługa połączenia odpowiednio, zgodnie z życzeniem.
Zobacz Jan Resig ' s post dla prostego wyjaśnienia tej techniki i ogólnie głębszego wyjaśnienia modelu dziedziczenia, który opowiada.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-30 19:06:01
Zgadzam się z pez i niektórymi tutaj.
Wydaje mi się oczywiste, że "nowe" jest samoopisowe tworzenie obiektów, gdzie wzór YUI opisany przez Grega Deana jest całkowicie przysłonięty .
Możliwość napisania var bar = foo;
LUB var bar = baz();
Gdzie baz nie jest metodą tworzenia obiektów wydaje się daleko bardziej niebezpieczna.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-20 17:10:39
Myślę, że nowy jest zły, nie dlatego, że jeśli zapomnisz go użyć przez pomyłkę, może to spowodować problemy, ale dlatego, że psuje łańcuch dziedziczenia, co sprawia, że język jest trudniejszy do zrozumienia.
JavaScript jest zorientowany obiektowo w oparciu o prototyp. Stąd każdy obiekt musi być utworzony z innego obiektu, takiego jak var newObj=Object.create(oldObj)
. Tutaj oldObj nazywa się prototypem newObj (stąd "prototype-based"). Oznacza to, że jeśli właściwość nie zostanie znaleziona w newObj, to będzie wyszukano w oldObj . newObj domyślnie będzie pustym obiektem, ale ze względu na łańcuch prototypów wydaje się, że posiada wszystkie wartościoldObj .
Z drugiej strony, jeśli zrobisz var newObj=new oldObj()
, prototyp newObj jest oldObj.prototyp , który jest niepotrzebnie trudny do zrozumienia.
The trick is to use
Object.create=function(proto){
var F = function(){};
F.prototype = proto;
var instance = new F();
return instance;
};
Jest wewnątrz tej funkcji i tylko tutaj Nowa powinna być używana. Po tym wystarczy użyć obiekt.metoda create () . Metoda rozwiązuje problem prototypu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-30 23:38:11