Quanto è pericoloso in JavaScript, in realtà, presumere che undefined non venga sovrascritto?


86

Ogni volta che qualcuno menziona il testing contro undefined, viene sottolineato che undefinednon è una parola chiave, quindi potrebbe essere impostata su"hello" , quindi dovresti usare typeof x == "undefined" invece. Questo mi sembra ridicolo. Nessuno lo farebbe mai, e se lo facessero sarebbe una ragione sufficiente per non usare mai alcun codice che hanno scritto ... giusto?

Ho trovato un esempio di qualcuno che ha impostato accidentalmente undefinedsu null, e questo è stato fornito come motivo per evitare di presumere che undefinednon venga sovrascritto. Ma se lo avessero fatto, il bug sarebbe passato inosservato e non vedo come sia meglio.

In C ++ tutti sanno bene che è legale dirlo #define true false, ma nessuno consiglia mai di evitarlo truee di usarlo 0 == 0. Presumi solo che nessuno sarebbe mai un idiota abbastanza grande da farlo, e se lo fanno, non fidarti mai più del loro codice.

Questo ha mai effettivamente morso qualcuno a cui qualcun altro era assegnato undefined(apposta) e ha rotto il tuo codice, o è più una minaccia ipotetica? Sono disposto a correre le mie possibilità per rendere il mio codice leggermente più leggibile. È davvero una cattiva idea?

Per ribadire, io non chiedendo come proteggere contro riassegnato indefinito. Ho già visto quei trucchi scritti 100 volte. Chiedo quanto sia pericoloso non usare quei trucchi.


7
Sarei felice di farlo, ma non credo che nessuna delle tre risposte fornite risponda bene alla domanda. Ho cercato di chiarire che non stavo chiedendo un rimaneggiamento delle risposte a cui mi collegavo, ma è comunque quello che ho ottenuto. Se è considerato goffo non accettare una risposta anche se non è quello che stavo chiedendo, fammelo sapere e io vado avanti e ne accetto una!
Cosmologicon

1
Penso che tutti i fatti siano esposti qui, però. Quindi, quello che stai dicendo è che vuoi invece una risposta o un'opinione soggettiva, il che porta solo al disaccordo. È il motivo per cui la frase "best practice" non è consentita nei titoli delle domande. Sei l'unica persona che può sapere quanto sia pericoloso nel tuo scenario. E se stai scrivendo una libreria popolare dove non controlli tutte le "variabili", il wrapper della funzione (non definito) {} sembra essere un'ottima risposta. Perché non usarlo e accettare quella risposta?
Shannon

4
Se qualcuno è preoccupato per qualcuno che ridefinisce undefined, dovresti preoccuparti di più per qualcuno che ridefinisce XMLHttpRequest, o alert. Tutte le funzioni da cui usiamo windowavrebbero potuto essere ridefinite. E se sei solo preoccupato che un collega lo faccia per sbaglio, perché fidarti che non lo faccia window.addEventListener = "coolbeans"? La risposta è non preoccuparsi di nulla di tutto ciò. Se qualcuno sta iniettando maliziosamente JS nella tua pagina, sei comunque ingannato. Lavora per evitare che ciò accada in primo luogo.
Chris Middleton

Risposte:


56

No, non l'ho mai fatto. Ciò è dovuto principalmente al fatto che sviluppo su browser moderni, che sono per lo più conformi a ECMAScript 5. Lo standard ES5 impone che undefinedora sia di sola lettura. Se usi la modalità rigorosa (dovresti), verrà generato un errore se provi accidentalmente a modificarlo.

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

Quello che non dovresti fare è creare il tuo mirato, mutabile undefined:

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

Constant va bene. Ancora inutile, ma va bene.

(function () {
    const undefined = void 0;
})();

La tua prima affermazione assicura solo che non sovrascrivi accidentalmente undefined durante lo sviluppo, ma rappresenta comunque la stessa minaccia quando viene eseguito con altro codice sui computer client.
bennedich

1
@bennedich: Lo so, stavo dicendo che non ho mai incontrato quel problema, ma ecco cosa dovresti fare .
Ry-

1
@bennedich Non hai la stessa possibilità di sovrascrivere accidentalmente altre variabili?
Ates Goral

40

Nessun codice corretto farà una cosa del genere. Ma non puoi mai sapere cosa ha fatto qualche sviluppatore aspirante o un plugin / libreria / script che stai usando. D'altra parte, è estremamente improbabile e i browser moderni non consentono affatto la sovrascrittura undefined, quindi se stai utilizzando un browser di questo tipo per lo sviluppo noterai rapidamente se qualche codice tenta di sovrascriverlo.


E anche se non l'hai chiesto, molte persone probabilmente troveranno questa domanda cercando il problema più comune "come proteggersi dalla ridefinizione undefined", quindi risponderò comunque:

C'è un ottimo modo per ottenere un'immagine davvero indefinita, undefined indipendentemente dall'età del browser:

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

Questo funziona perché un argomento non specificato è sempre undefined. Puoi anche farlo con una funzione che accetta alcuni argomenti reali, ad esempio come questo quando usi jQuery. Di solito è una buona idea garantire un ambiente sano in questo modo:

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

Quindi puoi essere sicuro che all'interno di quella funzione anonima sono vere le seguenti cose:

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

Tuttavia, nota che a volte typeof x === 'undefined'è effettivamente necessario: se la variabile xnon è mai stata impostata su un valore (al contrario di essere impostata su undefined), la lettura xin un modo diverso, ad esempio, if(x === undefined)genererà un errore. Ciò non si applica alle proprietà degli oggetti, quindi se sai che yè sempre un oggetto, if(y.x === undefined)è perfettamente sicuro.


2
La tua dichiarazione di xnon essere impostato su un valore non è del tutto vera (vedi jsfiddle.net/MgADz ); è piuttosto se in realtà non è davvero definito (vedere jsfiddle.net/MgADz/1 ).
Ry-

7
Di nuovo, se qualcuno accidentalmente dice undefined = someVariableche è un bug e vuoi che le cose si rompano. Almeno lo faccio.
Cosmologicon

2
Ho lavorato con una base di codice che aveva uno script legacy minimizzato che sovrascriveva undefined, non avevamo tempo o budget per riscrivere lo script, questo è un esempio in cui era richiesto typeof x == "undefined", non è così strano e probabilmente una buona abitudine.
Damen TheSifter

2
Sono interessato al motivo per cui tutti gli esempi utilizzano "undefined" come argomento aggiuntivo nella funzione? Ma ci possono essere situazioni se qualcuno passa un parametro extra (definito) per errore e tutta la logica fallirà. Perché non usare qualcosa come function () {var _undef; if (someVal == _undef) {do something}};
Oleksandr_DJ

4
@Oleksandr_DJ Esattamente. Crea un valore che sai essere undefinede assegnalo undefinednell'ambito. Non lasciare undefinedaperto per la sovrascrittura se si passano "troppi" argomenti. Ciò invita ad errori ed è un modello intrinsecamente non difensivo, soprattutto quando, come sottolinea Lucero , ci sono alternative molto facili per ottenere undefinedvalori solidi nell'ambito.
ruffin

19

C'è una soluzione semplice a questo: il confronto con il void 0quale è sempre indefinito.

Nota che dovresti evitare ==in quanto potrebbe forzare i valori. Usa ===(e !==) invece.

Detto questo, la variabile indefinita può essere impostata per errore se qualcuno scrive =invece di ==confrontare qualcosa con undefined.


IMO, questa è la migliore risposta.
abhisekp

1
Considera che foo === void 0potrebbe non essere letto così liscio come foo === undefinede che immutabile undefinedè completamente supportato dai browser moderni (IE 9+) come puoi vedere in questa tabella di compatibilità.
Daniel AR Werner

3

Solo tu sai quale codice usi e quindi quanto è pericoloso. Non è possibile rispondere a questa domanda nel modo in cui hai chiarito di volere una risposta.

1) Creare una politica del team, non consentire la ridefinizione di undefined, riservandolo per il suo utilizzo più popolare. Scansiona il tuo codice esistente per un'assegnazione sinistra non definita.

2) Se non controlli tutti gli scenari, se il tuo codice viene utilizzato al di fuori di situazioni controllate da te o dalle tue politiche, ovviamente la tua risposta è diversa. Scansiona il codice che utilizza i tuoi script. Diamine, scansiona il web per le statistiche di incarichi a sinistra indefiniti se lo desideri, ma dubito che sia stato fatto per te, perché è più facile cercare la risposta n. 1 o n. 3 qui invece.

3) E se quella risposta non è abbastanza buona, probabilmente è perché, ancora una volta, hai bisogno di una risposta diversa. Forse stai scrivendo una libreria popolare che verrà utilizzata all'interno dei firewall aziendali e non hai accesso al codice chiamante. Quindi usa una delle altre belle risposte qui. Nota la popolare libreria jQuery pratica l'incapsulamento del suono e inizia:

(function( window, undefined ) {

Solo tu puoi rispondere alla tua domanda nel modo specifico che cerchi. Che altro c'è da dire?

edit: ps se proprio vuoi la mia opinione, ti dico che non è affatto pericoloso. Tutto ciò che potrebbe causare difetti (come l'assegnazione a undefined, che è ovviamente un comportamento rischioso ben documentato) è di per sé un difetto. È il difetto che è il rischio. Ma questo è solo nei miei scenari, dove posso permettermi di mantenere quella prospettiva. Come ti consiglio di fare, ho risposto alla domanda per i miei casi d'uso.


3

È sicuro testare contro undefined. Come hai già detto. Se ottieni del codice che lo sovrascrive (che è altamente migliorabile), non usarlo più.

Forse se stai creando una libreria per uso pubblico, puoi usare alcune delle tecniche per evitare che l'utente la cambi. Ma anche in questo caso, è un problema loro, non della tua libreria.



1

Non è affatto pericoloso. Può essere sovrascritto solo quando si esegue su un motore ES3 e probabilmente non verrà più utilizzato.


0

Prima di tutto, se il tuo codice si rompe probabilmente non è perché qualche altro sviluppatore là fuori "sta cercando di essere un idiota" come dici tu.

È vero che undefinednon è una parola chiave. Ma è una primitiva a livello globale. Doveva essere usato in questo modo (vedi "undefined" su developer.mozilla.org ):

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

L'alternativa comune a quella (anche da MDN ) e secondo me il modo migliore è:

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

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

}

Il che ha un paio di vantaggi, quello ovvio (dai commenti) è che non fa scattare un'eccezione quando x non è dichiarato. E 'anche interessante notare che MDN sottolinea inoltre che è importante utilizzare ===nel corso ==nel primo caso perché:

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
}

Questo è un altro motivo spesso trascurato per cui è probabilmente meglio usare la seconda alternativa in tutti i casi.

Conclusione: non è sbagliato codificarlo nel primo modo, e certamente non pericoloso. L'argomento che hai visto che usi come esempio contro di esso (che può essere sovrascritto) non è l'argomento più forte per codificare l'alternativa con typeof. Ma l'uso typeofè più forte per un motivo specifico: non genera un'eccezione quando la tua var non è dichiarata. Si potrebbe anche sostenere che usare al ==posto di ===è un errore comune, nel qual caso non sta facendo quello che ti aspettavi. Allora perché non usare typeof?


1
"Il che ha un paio di vantaggi, quello ovvio è che non fa scattare un'eccezione quando x non è dichiarato." Fatemi capire bene. Pensi che sia un vantaggio ignorare silenziosamente l'eccezione che si verifica quando usi una variabile non dichiarata? Sembra molto soggetto a errori. Puoi spiegare perché pensi che non sia un terribile svantaggio?
Cosmologicon
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.