views:

2051

answers:

7

Say I have the following code:

function One() {}
One.prototype.x = undefined;

function Two() {}

var o = new One();
var t = new Two();

o.x and t.x will both evaluate to undefined. o.hasOwnProperty('x') and t.hasOwnProperty('x') will both return false; the same goes for propertyIsEnumerable. Two questions:

  • Is there any way to tell that o.x is defined and set to undefined?
  • Is there ever any reason to? (should the two be semantically equivalent?)

A small caveat: doing (for propName in o) loop will yield 'x' as one of the strings, while doing it in t will not - so there IS a difference in how they're represented internally (at least in Chrome).

A: 

One way to do it is this:

var definedProperties = [];
for (var prop in o) definedProperties.push(prop);

if (o.x === undefined && contains(prop, 'x')) {
    //x is defined, but set to undefined
}

where contains just checks whether any element in the array is 'x'. Is this the only way?

Claudiu
"contains" ? Thats not ECMAScript. Even if it was, your solution is way to slow and uses more resources than needed. Use "x in y" like it says in the other answers.
some
i know, i forgot ECMAScript had an 'in' operator =P.
Claudiu
A: 

You could try putting a watch on One.x but that would only tell you at the time it gets undefined.

nickf
Nope, he is defining it with the primitive value 'undefined'.
some
Undefining it would be using "delete".
Tomalak
rightio! edited now.
nickf
A: 

Something like this?

function isDefined(var){
   return (typeof(window[var]) == 'undefined') ? false : true;
}

or..

function isDefined(var){
   return (window.var === undefined) ? false : true;
}
adam
these will act the same for both variants, i think
Claudiu
+1  A: 

No. I don't think a variable equal to undefined should be recognized as "defined".

Setting it equal to undefined directly is just a lazy way of deleting it -- as apposed to using the delete keyword. I believe this just means that garbage collection hasn't taken affect on the variable/property.


[EDIT]

Regarding your comment about hasOwnProperty and propertyIsEnumerable, prototype methods/properties are neither the object's own nor enumerable.

Object.prototype.foo = 'something';

var o = {bar: 'anything'};
o.hasOwnProperty('foo');  //=> false
o.hasOwnProperty('bar');  //=> true

Object.prototype.hasOwnProperty('foo');  //=> true
Jonathan Lonowski
this is possible.
Claudiu
Setting it to the primitive value undefined don't delete the property, but you loose the reference to whatever the property contained. It has nothing to do with garbage collection not taken effect.
some
+9  A: 

A slightly simpler way than your method is to use the Javascript in operator

alert('x' in o); // true
alert('x' in t); // false
Greg
+1 for the correct answer.
some
duh.. silly me =).
Claudiu
+4  A: 

object.hasOwnProperty(name) only returns true for objects that are in the same object, and false for everything else, including properties in the prototype.

function x() {
  this.another=undefined;
};

x.prototype.something=1;
x.prototype.nothing=undefined;
y = new x;

y.hasOwnProperty("something"); //false
y.hasOwnProperty("nothing"); //false
y.hasOwnProperty("another"); //true

"someting" in y; //true
"another" in y; //true

Additionally the only way do delete a property is to use delete. Setting it to undefined do NOT delete it.

The proper way to do it is to use in like roborg said.

Update: undefined is a primitive value, see ECMAScript Language Specification section 4.3.2 and 4.3.9.

some
+1 for digging out the ECMA spec
Greg
+3  A: 

Ach, one for the anti-patterns thread there.

undefined is not a keyword.

When you assign write var foo = undefined; you are assigning it the value of the symbol undefined which you haven't defined and hence the value you'll get is "undefined". You would produce exactly the same result if you had assigned it UnDeFiNeD or NotFineAtAll or _qwertyuiop

Why is this so terrible? Well apart from the fact that it leads to a false understanding of what's going on, what happens if you happen to load a library or hire a dev who writes var undefined = true;

annakata
ah, very intersting. one note, however - setting it to "UnDeFiNed" will cause a compile-time error, as that variable is not defined. setting it to "Object.randomStringinserthereplease" acts the way you say it will.
Claudiu
you mean run-time, no such thing as compile with JS - but you're right, my description assumes scope. The problem arises because undefined can be treated as a constant in many situations and has been supported by some browsers, but it's *not* a constant and it isn't safe
annakata
If you want to know if something is undefined regardless of someone has changed the value of undefined: typeof x === "undefined"
some
@annakata: undefined is a primitive value, see section 4.3.9 of the ECMAScript specification. You are wrong when you say "you are assigning it the value of the symbol undefined which you haven't defined" (cont)
some
@annakata: However, you are right that it isn't a constant and that it will give unexpected behavior if undefined is defined to something else. So will this: eval=function(){alert("eval not supported anymore");}
some