Jak niebezpieczne jest w JavaScript założenie, że undefined nie jest nadpisywany?

86

Za każdym razem, gdy ktoś wspomina testowanie przeciwko undefined, wskazuje, że undefinednie jest to słowo kluczowe, więc można je ustawić na"hello" , więc powinieneś użyć typeof x == "undefined" zamiast tego. Wydaje mi się to śmieszne. Nikt nigdy by tego nie zrobił, a gdyby to zrobili, byłby to wystarczający powód, aby nigdy nie używać żadnego napisanego przez siebie kodu ... prawda?

Znalazłem jeden przykład kogoś, kto przypadkowo ustawił się undefinedna null, i został podany jako powód, aby uniknąć założenia, że undefinednie jest nadpisany. Ale gdyby to zrobili, błąd pozostałby niewykryty i nie wiem, jak to jest lepsze.

W C ++ wszyscy doskonale zdają sobie sprawę, że to legalne #define true false, ale nikt nigdy nie radzi, aby unikać truei używać 0 == 0zamiast tego. Po prostu zakładasz, że nikt nigdy nie byłby na tyle dużym palantem, żeby to zrobić, a jeśli tak, to nigdy więcej nie ufaj ich kodowi.

Czy kiedykolwiek ugryzło to kogoś, komu ktoś inny został przydzielony undefined(celowo) i złamało twój kod, czy jest to bardziej hipotetyczne zagrożenie? Jestem gotów zaryzykować, aby mój kod był nieznacznie bardziej czytelny. Czy to naprawdę zły pomysł?

Powtórzyć, ja nie z prośbą o jak chronić przed przeniesiony niezdefiniowane. Widziałem te sztuczki napisane już 100 razy. Pytam, jak niebezpieczne jest niestosowanie tych sztuczek.

Cosmologicon
źródło
7
Byłbym szczęśliwy, ale wydaje mi się, że żadna z trzech udzielonych odpowiedzi nie jest dobrą odpowiedzią na pytanie. Próbowałem wyjaśnić, że nie prosiłem o powtórzenie odpowiedzi, z którymi się łączyłem, ale wciąż to otrzymałem. Jeśli uważam, że nieprzyjęcie odpowiedzi, nawet jeśli nie jest to, o co prosiłem, uważane jest za głupie, daj mi znać, a ja zgodzę się na jedną!
Cosmologicon
1
Myślę jednak, że wszystkie fakty są tutaj przedstawione. Więc mówisz, że chcesz zamiast tego subiektywnej odpowiedzi lub opinii, co prowadzi tylko do nieporozumień. Z tego powodu wyrażenie „najlepsza praktyka” nie jest dozwolone w tytułach, o których mowa. Jesteś jedyną osobą, która może wiedzieć, jak niebezpieczne jest to w twoim scenariuszu. A jeśli piszesz popularną bibliotekę, w której nie kontrolujesz wszystkich „zmiennych”, opakowanie function (undefined) {} ​​wydaje się być doskonałą odpowiedzią. Dlaczego go nie wykorzystać i przyjąć tę odpowiedź?
shannon,
4
Jeśli ktoś martwi się, że ktoś przedefiniuje undefined, powinieneś bardziej martwić się tym, że ktoś przedefiniuje XMLHttpRequestlub alert. Wszystkie funkcje, z których korzystamy, windowmożna było przedefiniować. A jeśli martwisz się, że współpracownik zrobi to przez przypadek, dlaczego ufasz, że tego nie zrobi window.addEventListener = "coolbeans"? Odpowiedź brzmi: nie martw się o to. Jeśli ktoś złośliwie wstrzykuje JS na twoją stronę, i tak jesteś w błędzie. W pierwszej kolejności pracuj nad tym, aby temu zapobiec .
Chris Middleton

Odpowiedzi:

56

Nie, nigdy tego nie robiłem. Dzieje się tak głównie dlatego, że programuję na nowoczesnych przeglądarkach, które są w większości zgodne z ECMAScript 5. Standard ES5 mówi, że undefinedjest to teraz tylko do odczytu. Jeśli używasz trybu ścisłego (powinieneś), zostanie zgłoszony błąd, jeśli przypadkowo spróbujesz go zmodyfikować.

undefined = 5;
alert(undefined); // still undefined
'use strict';
undefined = 5; // throws TypeError

Co należy nie zrobić, to stworzyć swój własny lunetą, zmienny undefined:

(function (undefined) {
    // don't do this, because now `undefined` can be changed
    undefined = 5;
})();

Stała jest w porządku. Nadal niepotrzebne, ale w porządku.

(function () {
    const undefined = void 0;
})();
Ry-
źródło
Twoje pierwsze stwierdzenie zapewnia tylko, że nie nadpiszesz przypadkowo undefined podczas programowania, ale nadal stanowi to samo zagrożenie, gdy działa z innym kodem na komputerach klienckich.
bennedich
1
@bennedich: Wiem, mówiłem, że nigdy nie napotkałem tego problemu, ale oto, co powinieneś zrobić .
Ry-
1
@bennedich Czy nie masz takiej samej szansy na przypadkowe nadpisanie jakiejkolwiek innej zmiennej?
Ates Goral
40

Żaden poprawny kod tego nie zrobi. Ale nigdy nie możesz wiedzieć, co zrobił jakiś pragnący być mądry programista lub wtyczka / biblioteka / skrypt, którego używasz. Z drugiej strony jest to bardzo mało prawdopodobne, a nowoczesne przeglądarki w ogóle nie pozwolą na nadpisywanie undefined, więc jeśli używasz takiej przeglądarki do programowania, szybko zauważysz, czy jakikolwiek kod próbuje go nadpisać.


I chociaż o to nie prosiłeś - wiele osób prawdopodobnie znajdzie to pytanie, szukając bardziej powszechnego undefinedproblemu „jak się chronić przed przedefiniowaniem ”, więc i tak odpowiem:

Istnieje bardzo dobry sposób na uzyskanie naprawdę niezdefiniowanej przeglądarki, undefined niezależnie od tego, ile lat ma przeglądarka:

(function(undefined) {
    // your code where undefined is undefined
})();

To działa, ponieważ argument, który nie jest określony, jest zawsze undefined. Możesz to również zrobić za pomocą funkcji, która przyjmuje pewne rzeczywiste argumenty, np. W ten sposób, gdy używasz jQuery. Zwykle dobrym pomysłem jest zapewnienie zdrowego środowiska w następujący sposób:

(function($, window, undefined) {
    // your code where undefined is undefined
})(jQuery, this);

Wtedy możesz być pewien, że wewnątrz tej anonimowej funkcji są prawdziwe następujące rzeczy:

  • $ === jQuery
  • window === [the global object]
  • undefined === [undefined].

Należy jednak pamiętać, że czasami typeof x === 'undefined'jest to rzeczywiście konieczne: jeśli zmienna xnigdy nie została ustawiona na wartość (w przeciwieństwie do ustawienia na undefined), odczyt xw inny sposób, na przykład if(x === undefined)spowoduje błąd. Nie dotyczy to jednak właściwości obiektu, więc jeśli wiesz, że yzawsze jest to przedmiot, if(y.x === undefined)jest to całkowicie bezpieczne.

ThiefMaster
źródło
2
Twoje stwierdzenie o xbraku ustawienia wartości nie jest do końca prawdziwe (patrz jsfiddle.net/MgADz ); raczej, jeśli naprawdę nie jest zdefiniowany (patrz jsfiddle.net/MgADz/1 ).
Ry-
7
Ponownie, jeśli ktoś przypadkowo powie, undefined = someVariableże to błąd i chcesz , aby coś się zepsuło. A przynajmniej ja.
Cosmologicon
2
Pracowałem z bazą kodu, która miała zminimalizowany starszy skrypt, który nadpisał undefined, nie mieliśmy czasu ani budżetu na przepisanie skryptu, to jest przykład, w którym typeof x == "undefined" był wymagany, to nie jest takie dziwne i prawdopodobnie dobry nawyk.
Damen TheSifter
2
Interesuje mnie, dlaczego wszystkie przykłady używają „undefined” jako dodatkowego argumentu funkcji? Ale może się zdarzyć, że ktoś przekaże jeden dodatkowy parametr (zdefiniowany) przez błąd i cała logika zawiedzie. Dlaczego nie użyć czegoś takiego jak function () {var _undef; if (someVal == _undef) {zrób coś}};
Oleksandr_DJ
4
@Oleksandr_DJ Dokładnie. Wymyśl wartość, o której wiesz , że jest undefinedi przypisz ją do undefinedzakresu. Nie zostawiaj undefinedotwartego do nadpisania, jeśli przekażesz „zbyt wiele” argumentów. To zachęca do błędów i jest z natury nieobronnym wzorcem, zwłaszcza gdy, jak wskazuje Lucero , istnieją bardzo łatwe alternatywy dla uzyskania solidnych undefinedwartości w zakresie.
ruffin
19

Jest na to proste rozwiązanie: porównaj z void 0 którym jest zawsze niezdefiniowane.

Pamiętaj, że powinieneś tego unikać, ==ponieważ może to wymusić wartości. Użyj ===(i!==Zamiast tego ).

To powiedziawszy, niezdefiniowana zmienna może zostać ustawiona przez błąd, jeśli ktoś napisze =zamiast ==porównywać coś z undefined.

Lucero
źródło
IMO, to najlepsza odpowiedź.
abhisekp
1
Należy wziąć pod uwagę, foo === void 0że odczyt może nie być tak płynny, jak foo === undefinedi że niezmienny undefinedjest w pełni obsługiwany przez nowoczesne przeglądarki (IE 9+), jak widać w tej tabeli zgodności.
Daniel AR Werner
3

Tylko Ty wiesz, jakiego kodu używasz i jakie jest to niebezpieczne. Na to pytanie nie można odpowiedzieć w sposób, w jaki wyjaśniłeś, że chcesz na nie odpowiedzieć.

1) Utwórz zasady zespołowe, nie zezwalaj na przedefiniowanie undefined, rezerwując je dla bardziej popularnych zastosowań. Przeskanuj istniejący kod w poszukiwaniu niezdefiniowanego przypisania do lewej strony.

2) Jeśli nie kontrolujesz wszystkich scenariuszy, jeśli Twój kod jest używany poza sytuacjami, które Ty lub Twoja polityka kontroluje, to oczywiście Twoja odpowiedź jest inna. Zeskanuj kod, który używa twoich skryptów. Heck, przejrzyj sieć w poszukiwaniu statystyk niezdefiniowanego przypisania do lewej strony, jeśli chcesz, ale wątpię, że zostało to zrobione za Ciebie, ponieważ łatwiej jest po prostu znaleźć odpowiedź nr 1 lub nr 3 tutaj.

3) A jeśli ta odpowiedź nie jest wystarczająco dobra, to prawdopodobnie dlatego, że znowu potrzebujesz innej odpowiedzi. Być może piszesz popularną bibliotekę, która będzie używana w firmowych zaporach ogniowych i nie masz dostępu do kodu wywołującego. Następnie użyj tutaj jednej z pozostałych dobrych odpowiedzi. Zwróć uwagę, że popularna biblioteka jQuery stosuje enkapsulację dźwięku i zaczyna się:

(function( window, undefined ) {

Tylko Ty możesz odpowiedzieć na swoje pytanie w określony sposób. Cóż więcej można powiedzieć?

edit: ps jeśli naprawdę chcesz mojej opinii, powiem ci, że to wcale nie jest niebezpieczne. Wszystko, co mogłoby z dużym prawdopodobieństwem powodować defekty (takie jak przypisanie do undefined, co jest oczywiście dobrze udokumentowanym ryzykownym zachowaniem) samo w sobie jest wadą. To wada jest ryzykiem. Ale to tylko w moich scenariuszach, w których mogę sobie pozwolić na utrzymanie takiej perspektywy. Tak jak radziłbym, odpowiedziałem na pytanie dotyczące moich przypadków użycia.

Shannon
źródło
3

Testowanie na niezdefiniowane jest bezpieczne. Jak już wspomniałeś. Jeśli dojdziesz do kodu, który go zastępuje (co jest bardzo możliwe do ulepszenia), po prostu już go nie używaj.

Może jeśli tworzysz bibliotekę do użytku publicznego, możesz użyć niektórych technik, aby uniknąć zmiany przez użytkownika. Ale nawet w tym przypadku to ich problem, a nie twoja biblioteka.

Bart Calixto
źródło
2

Możesz użyć undefinedw swoim kodzie podczas kodowania dla przeglądarek obsługujących ECMAScript 5.1, ponieważ jest niezmienny zgodnie ze specyfikacją języka .

Zobacz także tabelę zgodności lub ten caniuse ECMAScript 5, aby zobaczyć, że wszystkie nowoczesne przeglądarki (IE 9+) mają zaimplementowaną niezmiennośćundefined .

Daniel AR Werner
źródło
1

To wcale nie jest niebezpieczne. Można go nadpisać tylko podczas pracy na silniku ES3 i prawdopodobnie nie będzie już używany.

kirk.burleson
źródło
0

Po pierwsze, jeśli twój kod się zepsuje, to prawdopodobnie nie dlatego, że jakiś inny programista „próbuje być kretynem”, jak to ujęłeś.

To prawda, że undefinednie jest to słowo kluczowe. Ale jest to prymitywny poziom globalny. Miał być używany w ten sposób (patrz „undefined” na developer.mozilla.org ):

var x;
if (x === undefined) {
    // these statements execute
}
else {
    // these statements do not execute
}

Wspólna alternatywa (również z MDN ) i moim zdaniem lepsza droga to:

// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
    // these statements execute
}

if(x === undefined){ // throws a ReferenceError

}

Ma to kilka zalet, oczywistą (z komentarzy) jest to, że nie wywołuje wyjątku, gdy x nie jest zadeklarowane. Warto również zauważyć, że MDN zwraca również uwagę, że w pierwszym przypadku ważne jest użycie ===over, ==ponieważ:

var x=null;
if (x === undefined) {
    // this is probably what you meant to do
    // these lines will not execute in this case
}
else if (x == undefined) {
    // these statements will execute even though x *is* defined (as null)
}
else {
    // these statements do not execute
}

Jest to kolejny, często pomijany powód, dla którego we wszystkich przypadkach lepiej jest po prostu używać drugiej alternatywy.

Wniosek: kodowanie go w pierwszej kolejności nie jest złe, a na pewno nie jest niebezpieczne. Argument, który widziałeś, którego używasz jako przykładu przeciwko niemu (że można go nadpisać), nie jest najsilniejszym argumentem za zakodowaniem alternatywy za pomocą typeof. Ale używanie typeofjest silniejsze konkretnie z jednego powodu: nie zgłasza wyjątku, gdy twoja zmienna nie jest zadeklarowana. Można również argumentować, że używanie ==zamiast ===jest częstym błędem, w którym to przypadku nie robi tego, czego się spodziewałeś. Dlaczego więc nie użyć typeof?

Ośmiornica
źródło
1
„Ma to kilka zalet, z których oczywistą jest to, że nie wywołuje wyjątku, gdy x nie jest zadeklarowane”. Pozwól mi sobie wyjaśnić. Myślisz, że dyskretne zignorowanie wyjątku, który ma miejsce, gdy używasz niezadeklarowanej zmiennej , jest zaletą ? Wydaje się to bardzo podatne na błędy. Czy możesz wyjaśnić, dlaczego uważasz, że to nie jest straszna wada?
Cosmologicon