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?


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

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:


if (sayThis === undefined) {   // Check to see if sayThis was passed
    sayThis = 'default value'; // It wasn't so give it a default value
}                              // End check

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:


var localVar = globalVar ? globalVar : defaultValue;

if (!variable) {
    variable = something;
}

if (variable) {
    use(variable);
}

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


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

pontosan ugyanaz, mint a


var myModule;

if (!myModule) {
    myModule = (function() { /* ... */ })();
}

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


if (typeof myVar == 'undefined') {
    myVar = defaultValue;
}

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:


var undefined = (function () {})();

var a = [];
a[1]  = undefined

var print = function(place, index, element) {
    $('#' + place).append($('<div>' + index + ': ' + element + '</div>'));
};

a.forEach(function(element, index) {
    print('forEach', index, element);
}); // 1: undefined

$.each(a, function(index, element) {
    print('jQuery', index, element);
}); // 0: undefined, 1: undefined

for(i = 0;  i < a.length; i++) {
    print('because', i, i in a);
}; // 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:


X = function () {
    this.undef1 = (function () {})();
}

Y = function() {
    this.undef1 = this.undef2 = 'UNDEFINED?';
}

var x = new X();

alert(x.undef1 + ', ' + x.undef2); // undefined, undefined

X.prototype = new Y();
var y       = new X();

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.

window.a == undefined // true, érték
typeof window.a // "undefined", típus
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.

window.lol // undefined
typeof window.lol // "undefined"
window.lol = null;
window.lol; // null
typeof window.lol; // "object"
delete window.lol;
window.lol // undefined
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.
var undef1;
typeof undef1 // "undefined", típus
typeof undef2 // "undefined", típus
undef1 // undefined, érték
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.
var obj = {};
obj.undef1 = (function(){})();
typeof obj.undef1 // "undefined", típus
typeof obj.undef2 // "undefined", típus
obj.undef1 // undefined, érték
obj.undef2 // undefined, érték
Az obj.undef1 nem definiált, az obj.undef2 nem deklarált.
'undef1' in obj // true
'undef2' in obj // false
for( var 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.