Best test for undefined?

N

nick

What's the "best" way to determine if a variable is defined?

I see a lot of code that looks like this:

// example 1
if (typeof x !== 'undefined') doStuff(x);

It won't throw an exception if you use it to operate on an undeclared
or deleted identifier.

If you're only testing declared variables, which seems like a
reasonable design decision, and are targeting only modern browsers you
could write this ():

// example 2
if (x !== undefined) doStuff(x);

Here's another way you could do it... I've rarely see it written like
this, but it gives the same result and should work in older browsers:

// example 3
if (x !== void 0) doStuff(x);

The third example is the most concise. The 'void' operator has been
around pretty much forever. I'm no js optimization expert, but I can't
imagine it being much less efficient than the first example.

The third example doesn't read as well as the second example, but (to
me) it's about as clear as the first, and with less room for error
(quoted string 'undefined' can be mistyped and not caught right away).

Is there any good reason not to use the 'void' operator to check
whether something is defined, assuming the author knows the variable
has been declared? Or is this another one of those things that has
been remembered and forgotten?

function isDefined (v) { return (v !== void 0) }
 
D

David Mark

nick said:
What's the "best" way to determine if a variable is defined?

I see a lot of code that looks like this:

// example 1
if (typeof x !== 'undefined') doStuff(x);

You don't need to do a strict comparison there. The typeof operation
returns a string.
It won't throw an exception if you use it to operate on an undeclared
or deleted identifier.

If you're only testing declared variables, which seems like a
reasonable design decision, and are targeting only modern browsers you
could write this ():

// example 2
if (x !== undefined) doStuff(x);

If x will be either be undefined or a "truthy" value (e.g. won't be
null), use boolean type conversion:-

if (x) {
doStuff(x);
}

That's something to think about at the design stage as well.
Here's another way you could do it... I've rarely see it written like
this, but it gives the same result and should work in older browsers:

// example 3
if (x !== void 0) doStuff(x);

The third example is the most concise.

Do you mean the most compatible? AFAIK, it only beats #2 in that
category (and only in very ancient browsers).
The 'void' operator has been
around pretty much forever. I'm no js optimization expert, but I can't
imagine it being much less efficient than the first example.

Neither can I.
The third example doesn't read as well as the second example, but (to
me) it's about as clear as the first, and with less room for error
(quoted string 'undefined' can be mistyped and not caught right away).

It's less error-prone than the second for sure as the global - undefined
- value could be shadowed. As for mistyping 'undefined', that's a good
point. Don't do that. :) Perhaps use a macro? And if you will need
to make such comparisons often (and performance is not an issue), put
the test in a function.
Is there any good reason not to use the 'void' operator to check
whether something is defined, assuming the author knows the variable
has been declared? Or is this another one of those things that has
been remembered and forgotten?

function isDefined (v) { return (v !== void 0) }

Not that I know of, but I find it to be less intuitive.
 
D

David Mark

Bart said:
Carefull: x = 0 and x = "" both produce a false, too.

Example given; it wasn't meant to be a complete reference of "falsey"
values. And which did you leave out? :)
 
B

Bart Lateur

David said:
If x will be either be undefined or a "truthy" value (e.g. won't be
null), use boolean type conversion:-

if (x) {
doStuff(x);
}

Carefull: x = 0 and x = "" both produce a false, too.
 
G

Garrett Smith

nick said:
What's the "best" way to determine if a variable is defined?

Depends. If conditional assignment results in an object value, e.g.

var x;
if(Math.random() > .5) {
x = {};
}


- then why not use boolean conversion?

if(x) {
// It has been assigned.
}
I see a lot of code that looks like this:

// example 1
if (typeof x !== 'undefined') doStuff(x);

It won't throw an exception if you use it to operate on an undeclared
or deleted identifier.

Works fine for undeclared identifiers and useful for host object checks,
too.

Identifiers that are declared with var get DontDelete, so don't worry
about the case where they were deleted -- they can't be.

For other values, it is useful to make different checks, depending on
what the code needs ot know.

For an example, checking to see if a variable had been assigned a good
number value, you might use:

var myNum = getPageCoords(ery);

if(isFinite(myNum)) {
// Move ery to new position.
}
function isDefined (v) { return (v !== void 0) }

That tells if a value is not undefined. The isDefined function in the
general sense does not provide any advantage over an inline check.

It does not say, in the general sense, if `v` has been declared, doese
not say if has been assigned a value (undefined is a value), does not
say if `v` is a variable, a property of something, the result of trying
to get a property that was not available.

Consider that, given function scope:

(function(){

var undef, myVar;
//...
var isDef = isDefined(myVar);
var isDef2 = myVar !== undef;
})();

For the cost of a function call, plus organizing and managing that
function, it is not worth it.
 
D

Dmitry A. Soshnikov

But isn't strict comparision faster than loose comparision?

Theoretically or practically? If practically, you can test it yourself
in every possible implementations and provide us with the results (maybe
it will be useful for someone).

In theoretically, for e.g. ES3 see 11.9.3 and 11.9.4. Let's compare them
(the steps which are essential for our case -- when operands have _the
same_ types such as in mentioned `typeof` check):

11.9.3 The Abstract Equality Comparison Algorithm:

1. If Type(x) is different from Type(y), go to step 14.
2. If Type(x) is Undefined, return true.
3. If Type(x) is Null, return true.
4. If Type(x) is not Number, go to step 11.
5. If x is NaN, return false.
6. If y is NaN, return false.
7. If x is the same number value as y, return true.
8. If x is +0 and y is −0, return true.
9. If x is −0 and y is +0, return true.
10. Return false.


And now the strict one:


11.9.6 The Strict Equality Comparison Algorithm

1. If Type(x) is different from Type(y), return false.
2. If Type(x) is Undefined, return true.
3. If Type(x) is Null, return true.
4. If Type(x) is not Number, go to step 11.
5. If x is NaN, return false.
6. If y is NaN, return false.
7. If x is the same number value as y, return true.
8. If x is +0 and y is −0, return true.
9. If x is −0 and y is +0, return true.
10. Return false.


We can omit step 1, because in our case types are equal -- we have
String type.

And then you can see that both algorithms are completely equivalent --
(word for word!).

So this is a big (and that is petty -- a wide spread) misconception. And
this misconception is obtruded by the _subjective meaning_ of some
authority. No more, no less. I repeat several times, that checks with
`typeof` comparing with strings and using === just looks ridiculous.

There is no any sense to use === with such checks. Because there is no
logical answer on:

(1) you know that `typeof` always produces string;
(2) you (yourself, by your own hands, but nobody else) compare this
result with a string.

Is there any reason (except "I just like", "that's to keep common
stylistics", "to be consecutive") to use ===?

Of course, if you accept it with reasons-"exceptions" which I just
mentioned -- that's your choice and your right. But please (I'm asking
everyone), let us don't call == as a "bad practice" and don't say that
this is about avoiding errors and etc. arguing (trying to argue)
_logically_.

This misconception is wide spread in _every_ popular framework.

Recently, I was reviewing one book (which should appear soon on
bookshelves) and there also == is named as a "bad practice" and
everywhere is used === including `typeof` with a string comparison on
the right hand side. (although, as a whole, the book is quite good with
professional approach). I recommended (if the author still want to keep
the general common stylistic using === everywhere), just to make a
_small note_ such as: "but in some case, e.g. with typeof operator when
we compare its result with strings, === is obsolete".

Dmitry.
 
D

Dmitry A. Soshnikov

On 10.05.2010 15:18, Dmitry A. Soshnikov wrote:

[...]
This misconception is wide spread in _every_ popular framework.


Yeah, forgot. That's at the same time when they fight trying to save
every byte minimizing/obfuscating scripts. And everywhere using === they
loose this one byte every time :D But, of course that isn't the main
reason. The main reason is -- that should be definite understanding of
what we are doing, but not just using that because some authority said so.

What about personally me -- I always use ==, and rarely === -- when it
is really needed.

Dmitry.
 
I

Ivan S

Theoretically or practically? If practically, you can test it yourself
in every possible implementations and provide us with the results (maybe
it will be useful for someone).

In theoretically, for e.g. ES3 see 11.9.3 and 11.9.4. Let's compare them
(the steps which are essential for our case -- when operands have _the
same_ types such as in mentioned `typeof` check):

11.9.3 The Abstract Equality Comparison Algorithm:

1. If Type(x) is different from Type(y), go to step 14.
2. If Type(x) is Undefined, return true.
3. If Type(x) is Null, return true.
4. If Type(x) is not Number, go to step 11.
5. If x is NaN, return false.
6. If y is NaN, return false.
7. If x is the same number value as y, return true.
8. If x is +0 and y is -0, return true.
9. If x is -0 and y is +0, return true.
10. Return false.

And now the strict one:

11.9.6 The Strict Equality Comparison Algorithm

1. If Type(x) is different from Type(y), return false.
2. If Type(x) is Undefined, return true.
3. If Type(x) is Null, return true.
4. If Type(x) is not Number, go to step 11.
5. If x is NaN, return false.
6. If y is NaN, return false.
7. If x is the same number value as y, return true.
8. If x is +0 and y is -0, return true.
9. If x is -0 and y is +0, return true.
10. Return false.

We can omit step 1, because in our case types are equal -- we have
String type.

And then you can see that both algorithms are completely equivalent --
(word for word!).

So this is a big (and that is petty -- a wide spread) misconception. And
this misconception is obtruded by the _subjective meaning_ of some
authority. No more, no less. I repeat several times, that checks with
`typeof` comparing with strings and using === just looks ridiculous.

There is no any sense to use === with such checks. Because there is no
logical answer on:

(1) you know that `typeof` always produces string;
(2) you (yourself, by your own hands, but nobody else) compare this
result with a string.

Is there any reason (except "I just like", "that's to keep common
stylistics", "to be consecutive") to use ===?

Of course, if you accept it with reasons-"exceptions" which I just
mentioned -- that's your choice and your right. But please (I'm asking
everyone), let us don't call == as a "bad practice" and don't say that
this is about avoiding errors and etc. arguing (trying to argue)
_logically_.

This misconception is wide spread in _every_ popular framework.

Recently, I was reviewing one book (which should appear soon on
bookshelves) and there also == is named as a "bad practice" and
everywhere is used === including `typeof` with a string comparison on
the right hand side. (although, as a whole, the book is quite good with
professional approach). I recommended (if the author still want to keep
the general common stylistic using === everywhere), just to make a
_small note_ such as: "but in some case, e.g. with typeof operator when
we compare its result with strings, === is obsolete".

Thanks for your answer. I wasn't trying to imply that loose comparison
is bad practice, I was asking with logical presumption. Thanks again
for your tehnical explanation! :)



Ivan
 
T

Tim Streater

Dmitry A. Soshnikov said:
On 10.05.2010 15:18, Dmitry A. Soshnikov wrote:

[...]
This misconception is wide spread in _every_ popular framework.


Yeah, forgot. That's at the same time when they fight trying to save
every byte minimizing/obfuscating scripts. And everywhere using === they
loose this one byte every time :D

Hey Dmitry you can save a byte every time by spelling "lose" as "lose"
(correct) rather than "loose" (incorrect and completely different word)
:)
 
D

Dmitry A. Soshnikov

Dmitry A. Soshnikov said:
On 10.05.2010 15:18, Dmitry A. Soshnikov wrote:

[...]
This misconception is wide spread in _every_ popular framework.


Yeah, forgot. That's at the same time when they fight trying to save
every byte minimizing/obfuscating scripts. And everywhere using === they
loose this one byte every time :D

Hey Dmitry you can save a byte every time by spelling "lose" as "lose"
(correct) rather than "loose" (incorrect and completely different word)
:)

Ah, great :p Thanks!

(sorry for English typos).

Dmitry.
 
T

Tim Streater

Dmitry A. Soshnikov said:
Dmitry A. Soshnikov said:
On 10.05.2010 15:18, Dmitry A. Soshnikov wrote:

[...]

This misconception is wide spread in _every_ popular framework.


Yeah, forgot. That's at the same time when they fight trying to save
every byte minimizing/obfuscating scripts. And everywhere using === they
loose this one byte every time :D

Hey Dmitry you can save a byte every time by spelling "lose" as "lose"
(correct) rather than "loose" (incorrect and completely different word)
:)

Ah, great :p Thanks!

(sorry for English typos).

No problem, I'm not having a go at you, just found a (slightly) amusing
opportunity to point it out. This is a common error but of course
everyone copies each other. I have done this myself in the past when
learning French from other non-French-mother-tongue people.
 
N

nick

Depends. If conditional assignment results in an object value
[...] then why not use boolean conversion?
if(x) { [...]

True, I guess I should have mentioned it for the sake of completeness.
I'm really more concerned with undefined vs. not undefined ATM, but
this would be good to include in a FAQ entry or something, along with
'in'.
Identifiers that are declared with var get DontDelete, so don't worry
about the case where they were deleted -- they can't be.

Interesting. So deleting them just leaves their value as-is, huh?

The console in Chromium tricked me. Look at this:

var x=5; alert(x); delete x; alert(x);
// alerts "5"
// throws ReferenceError: x is not defined

I figured I had successfully deleted the var. But this line acts
totally different:

(function(){var x=5; alert(x); delete x; alert(x);})()
// alerts "5" twice
// function returns undefined as normal

Looks like there's some serious black magic being performed by the
console in the first example.
For other values, it is useful to make different checks, depending on
what the code needs ot know. [...]
Agreed.
  function isDefined (v) { return (v !== void 0) }
That tells if a value is not undefined. The isDefined function in the
general sense does not provide any advantage over an inline check.

That's true; If there's going to be a function call the function could
just be a no-op (returning undefined).
It does not say, in the general sense, if `v` has been declared,

What do you mean? 'v' is declared as an argument to isDefined, right?
That was sort of the point of this example.
does not say if has been assigned a value (undefined is a value), does not
say if `v` is a variable, a property of something, the result of trying
to get a property that was not available.

Ok, I see what you're getting at.
Consider that, given function scope:
(function(){
   var undef, myVar;
  //...
   var isDef = isDefined(myVar);
   var isDef2 = myVar !== undef;
})();

Hmm, I'm not totally sold. If we're going to do it like that why not
just shadow the global undefined and use that?
For the cost of a function call, plus organizing and managing that
function, it is not worth it.

You are probably right. That function was not really the ultimate
point of the OP, it was just an example of a way to check for things
having a value of undefined (inline or otherwise) using the syntax
that I liked the most of the three examples above.

Still, I sort of like the idea of encapsulating it in a function.
David's macro idea is starting to sound pretty good...

//#define UNDEFINED void 0
//#define IS_DEFINED(v) (v !== UNDEFINED)

That should do it. :D
 
R

Ry Nohryb

Interesting. So deleting them just leaves their value as-is, huh?

The delete operator is intended to delete *properties*of*objects* not
vars, and only global vars happen to be properties of an object (of
the global object). Applying delete to a non-global or to a non-
existent var will just do nothing.

A global var "x" exists if ("x" in window) is true (in any browser
except probably in Microsoft's Internet Explorer due to another of its
long long list of long standing never fixed / won't fix bugs). The
existence of a local var "x" is a lot harder to detect unequivocally.
 
V

VK

The delete operator is intended to delete *properties*of*objects* not
vars, and only global vars happen to be properties of an object (of
the global object). Applying delete to a non-global or to a non-
existent var will just do nothing.

Applying delete to window properties or Javascript variables leads to
run-time error in IE. The *only* legal use of delete operator is for
Object instances, properties of Object instances and for elements of
Array instances. The docs are pretty explicit on it though:
http://docs.sun.com/source/816-6408-10/ops.htm#1045837

About undefined it is worth to mention IMO the most sick and bizarre
Javascript feature: the possibility to assign undefined value so
instantiating variables with value "I am not instantiated", see
"undefined vs. undefined" discussion at
http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/60004636376462c/

The purpose and the meaning of it remain a mystery to me, I assume
some minds were severely distracted at the time of introducing this
feature. Respectively Javascript has two undefined values with
different behavior but without an easy way to distinguish them:

var foo = undefined;

alert(typeof foo); // "undefined"

alert(foo); // "undefined"

alert(typeof bar); // "undefined"

alert(bar); // "bar is not defined" run-time error

Lucky this has purely theoretical importance: the idioticy of
assigning "not assigned" value, so keeping the identifier in the scope
yet forcing it to say "I don't exist", cannot be met in any descent
code.
 
G

Garrett Smith

nick said:
Depends. If conditional assignment results in an object value
[...] then why not use boolean conversion?
if(x) { [...]

True, I guess I should have mentioned it for the sake of completeness.
I'm really more concerned with undefined vs. not undefined ATM, but
this would be good to include in a FAQ entry or something, along with
'in'.

Sure. However there is some catchall behavior that does not provide
hooks for "has". Some catchall implementations exist with host objects
such as any of the dom collections or navigator.plugins.

javascript: alert(
["Shockwave Flash" in navigator.plugins ,
navigator.plugins["Shockwave Flash"] ]);

The example code shows in Firefox 3.6 "false, [object Plugin]".

The `in` operator indicates that the plugin property does not exists yet
[[Get]] results in the desired plugin object.
Interesting. So deleting them just leaves their value as-is, huh?

Check result of calling delete.

var x;
alert(delete x); // false.
The console in Chromium tricked me. Look at this:
[...]

Chrome console likely uses eval.

For eval code:
| Variable instantiation is performed using the calling context's
| variable object and using empty property attributes.

That means there is no DontDelete.

See also:
http://perfectionkills.com/understanding-delete/#firebug_confusion
http://groups.google.am/group/comp..../thread/8604c3c08794dc34#msg_cb73090b3da02eda
For other values, it is useful to make different checks, depending on
what the code needs ot know. [...]
Agreed.
function isDefined (v) { return (v !== void 0) }
That tells if a value is not undefined. The isDefined function in the
general sense does not provide any advantage over an inline check.

That's true; If there's going to be a function call the function could
just be a no-op (returning undefined).

an isXXX function should return a boolean value.
What do you mean? 'v' is declared as an argument to isDefined, right?
That was sort of the point of this example.

The only way for isDefined to if `v` was passed in is to check
arguments.length.
Ok, I see what you're getting at.

What I am getting at is that the function removed from context tells
less than can be deduced in context. It does not differentiate any of
the cases:

var o = {};
isDefined(o.blah);
o.blah = Function.prototype();
isDefined(undefined);
var x;
isDefined(x);
x = undefined;
isDefined(x);

Hmm, I'm not totally sold. If we're going to do it like that why not
just shadow the global undefined and use that?

OK.


You are probably right. That function was not really the ultimate
point of the OP, it was just an example of a way to check for things
having a value of undefined (inline or otherwise) using the syntax
that I liked the most of the three examples above.

Still, I sort of like the idea of encapsulating it in a function.

What for?
 
L

Lasse Reichstein Nielsen

nick said:
Interesting. So deleting them just leaves their value as-is, huh?

The console in Chromium tricked me. Look at this:

var x=5; alert(x); delete x; alert(x);
// alerts "5"
// throws ReferenceError: x is not defined

I figured I had successfully deleted the var. But this line acts
totally different:

(function(){var x=5; alert(x); delete x; alert(x);})()
// alerts "5" twice
// function returns undefined as normal

Looks like there's some serious black magic being performed by the
console in the first example.

No black magic necessary, it probably just uses a direct call to
"eval" to evaluate the input. The expected behavior of variables
created in an eval code is to make them configurable (deletable),
wheras variables in program or function code are not configurable.
(See ECMAScript 5, section 10.5).

/L 'Know thy spec'.
 
B

Bart Lateur

David said:
Example given; it wasn't meant to be a complete reference of "falsey"
values. And which did you leave out? :)

Well...

I'm wondering why in the original question

if (x == null) {
doStuff(x);
}

won't do.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top