ugrás a tartalomhoz

undefined !== undefined

presidento · 2010. Május. 11. (K), 08.34

Mit ír ki az alábbi JavaScript program, ha az első két alert: 1: undefined és 2: undefined?

  1. alert('1: ' + typeof undef1);  
  2. alert('2: ' + typeof undef2);  
  3. alert('3: ' + undef1);  
  4. alert('4: ' + undef2);  
  5. // ...  

A válasz: nem tudjuk biztosan.

Nálam jelen esetben: 3: undefined és semmi más. Ugyanis a három pontban elrejtettem egy var undef1; deklarációt, így az undef1 változó létezik, de nincs értéke, míg az undef2 változó nem is létezik. Ezért a negyedik alertnél hibával elszáll a szkript (undef2 is not defined – milyen meglepő).

A nagy kérdés ez: Hogyan adjunk egy változónak alapértelmezett értéket, ha undefined?

Ezen az ajánlott JavaScript oldalon a következőt olvashatjuk:

  1. if (sayThis === undefined) {   // Check to see if sayThis was passed  
  2.     sayThis = 'default value'// It wasn't so give it a default value  
  3. }                              // End check  
  4.   
  5. alert(sayThis);                // Toss up the alert.  

Ezzel több probléma van, például, hogy nem tudhatjuk, az undefined változó valóban undefined-e.

Sajnos a következők sem megfelelők, hiszen ha a vizsgált változónk nem létezik, a futás megszakad:

  1. var localVar = globalVar ? globalVar : defaultValue;  
  2.   
  3. if (!variable) {  
  4.     variable = something;  
  5. }  
  6.   
  7. if (variable) {  
  8.     use(variable);  
  9. }  

Ha létrehozni akarjuk a változót, akkor nincs gond, hiszen mindegy, hogy a hatókörön belül hova helyezzük el a változó deklarációját: az

  1. if (!myModule) {  
  2.     var myModule = (function () { /* ... */ })();  
  3. }  

pontosan ugyanaz, mint a

  1. var myModule;  
  2.   
  3. if (!myModule) {  
  4.     myModule = (function() { /* ... */ })();  
  5. }  

A minden körülmények között biztonságos módszer:

  1. if (typeof myVar == 'undefined') {  
  2.     myVar = defaultValue;  
  3. }  

A lokális változókkal nincsenek gondok, hiszen éppen attól lokálisak, hogy a var kulcsszóval vagy a függvény paramétereiként létrehoztuk őket.

Egy objektum tulajdonságai mindig léteznek* (még akkor is, ha nincsenek definiálva). A JavaScriptben minden globális változó a self (vagy window) adattagja, azaz globalVar === self.globalVar igaz minden esetben (ha a változó létezik). Emiatt biztonsággal használhatjuk a var localVar = self.globalVar ? globalVar : defaultValue; kifejezést is. (A globális névtérben ugyanis lokálisan a self és window is helyettesíthető mással.)

* Pongyola fogalmazás, itt is megjelenik a kétféle undefined:

  1. var undefined = (function () {})();  
  2.   
  3. var a = [];  
  4. a[1]  = undefined  
  5.   
  6. var print = function(place, index, element) {  
  7.     $('#' + place).append($('<div>' + index + ': ' + element + '</div>'));  
  8. };  
  9.   
  10. a.forEach(function(element, index) {  
  11.     print('forEach', index, element);  
  12. }); // 1: undefined  
  13.   
  14. $.each(a, function(index, element) {  
  15.     print('jQuery', index, element);  
  16. }); // 0: undefined, 1: undefined  
  17.   
  18. for(i = 0;  i < a.length; i++) {  
  19.     print('because', i, i in a);  
  20. }; // 0: false, 1: true  

A natív forEach (vagy az MDC oldalán javasolt megoldás) ezt szépen lekezeli, a jQuery azonban nem ismeri fel, hogy a 0-s elem nincs a tömbben.

Hasonló a helyzet az objektumoknál:

  1. X = function () {  
  2.     this.undef1 = (function () {})();  
  3. }  
  4.   
  5. Y = function() {  
  6.     this.undef1 = this.undef2 = 'UNDEFINED?';  
  7. }  
  8.   
  9. var x = new X();  
  10.   
  11. alert(x.undef1 + ', ' + x.undef2); // undefined, undefined  
  12.   
  13. X.prototype = new Y();  
  14. var y       = new X();  
  15.   
  16. alert(y.undef1 + ', ' + y.undef2); // undefined, UNDEFINED?  

Az undef1 nem definiált, az undef2 nem létezik. Ezért ha van prototípus, az undef2 megkapja onnan az értékét.

Konklúzió: jobb lett volna, ha van undefined és nonexists típus, de ha már így alakult, ne felejtkezzünk meg arról, mindkettő létezik, csak ugyanazon undefined név alatt.

Adódik a kérdés: ezek után mit keres a null a nyelvben? ;) Ennek megválaszolását az Olvasóra bízom.

 
1

Elvesztettem a fonalat.

Török Gábor · 2010. Május. 10. (H), 16.13
Elvesztettem a fonalat. JavaScriptben egy változó lehet deklarált és definiált. Minden var kulcsszóval bevezetett változó deklarált. Ha egy változó deklarált, de nincs még értéke, akkor a változó értéke undefined. Ha egy változó nem deklarált, akkor annak típusa "undefined". Ez a kétfajta undefined valóban nem identikus, lévén egyik típus, másik érték. Az undefined érték típusa is undefined. Explicit visszatérés nélkül konstruált függvény undefined értékkel tér vissza.

Egy objektum tulajdonságai mindig léteznek* (még akkor is, ha nincsenek definiálva).

Tehát nem definiálva nincsen, hanem deklarálva. Ez pedig a JavaScript azon természetéből fakad, hogy ha egy objektum nemlétező tulajdonságára hivatkozunk, akkor undefined értéket kapunk vissza.
  1. window.a == undefined // true, érték  
  2. typeof window.a // "undefined", típus  
  3. typeof window.a == window.a // false  
A null értékkel pedig deklarált változót (vagy objektum tulajdonságot) hozhatunk olyan helyzetbe, hogy noha nyelvtanilag definiált, de magasabb szintű logika szerint ne legyen az.
  1. window.lol // undefined  
  2. typeof window.lol // "undefined"  
  3. window.lol = null;  
  4. window.lol; // null  
  5. typeof window.lol; // "object"  
  6. delete window.lol;  
  7. window.lol // undefined  
  8. typeof window.lol // "undefined"  
3

Nem csodálom

presidento · 2010. Május. 11. (K), 16.16
Most visszaolvasva nekem is kusza, este volt már. :)
Ez a kétfajta undefined valóban nem identikus, lévén egyik típus, másik érték.

Éppen ezt szerettem volna kihangsúlyozni, ezek szerint nem sikerült jól megfogalmaznom.
  1. var undef1;  
  2. typeof undef1 // "undefined", típus  
  3. typeof undef2 // "undefined", típus  
  4. undef1 // undefined, érték  
  5. undef2 // futási hiba  
Az undef1 nem definiált, az undef2 nem deklarált. Bár mindkettő "típusa" (typeof-ja) megegyezik, ha nem deklarált változót használunk értékadásban, a script futása megszakad.
  1. var obj = {};  
  2. obj.undef1 = (function(){})();  
  3. typeof obj.undef1 // "undefined", típus  
  4. typeof obj.undef2 // "undefined", típus  
  5. obj.undef1 // undefined, érték  
  6. obj.undef2 // undefined, érték  
Az obj.undef1 nem definiált, az obj.undef2 nem deklarált.
  1. 'undef1' in obj // true  
  2. 'undef2' in obj // false  
  3. forvar prop in obj ) alert(prop) // [undef1]  
2

OFF

Adam · 2010. Május. 11. (K), 08.53
Csak nekem tetszik így jobban a weblabor, hogy monospace lett a font?
4

Sajnálom

Joó Ádám · 2010. Május. 11. (K), 23.42
Elírás folytán rosszul formázott volt a HTML. Nincs monospace.