By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,122 Members | 1,555 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,122 IT Pros & Developers. It's quick & easy.

Validating existence of "deep" object

P: n/a
Consider the following two functions:

function func1() {
var o ;
if ( (o=document.forms)
&& (o=o[0])
&& (o=o.elements)
&& (o=o.sel)
&& (o=o.options)
&& (o=o[0])
&& (o=o.value)
) {
return true;
}
return false;
}

function func2() {
if (document.forms
&& document.forms[0]
&& document.forms[0].elements
&& document.forms[0].elements.sel
&& document.forms[0].elements.sel.options
&& document.forms[0].elements.sel.options[0]
&& document.forms[0].elements.sel.options[0].value)
{
return true;
}
return false;
}

The perform the same function of making sure that the entire object chain
exists before trying to reference the "deep" object. This may not be a
perfect example, but in some cases it is definitely necessary to validate
all the way down the object chain that things exist how you expect them to
(for example, a json response).

The first function seems to run 3-5x faster in IE and FF, as I would expect
it to.

Is there a cleaner way to write the first function to get the same
functionality but be more readable?

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com
Feb 16 '07 #1
Share this Question
Share on Google+
15 Replies


P: n/a
On Feb 16, 6:35 am, "Matt Kruse" <newsgro...@mattkruse.comwrote:
Consider the following two functions:

function func1() {
var o ;
if ( (o=document.forms)
&& (o=o[0])
&& (o=o.elements)
&& (o=o.sel)
&& (o=o.options)
&& (o=o[0])
&& (o=o.value)
) {
return true;
}
return false;

}

function func2() {
if (document.forms
&& document.forms[0]
&& document.forms[0].elements
&& document.forms[0].elements.sel
&& document.forms[0].elements.sel.options
&& document.forms[0].elements.sel.options[0]
&& document.forms[0].elements.sel.options[0].value)
{
return true;
}
return false;

}

The perform the same function of making sure that the entire object chain
exists before trying to reference the "deep" object. This may not be a
perfect example, but in some cases it is definitely necessary to validate
all the way down the object chain that things exist how you expect them to
(for example, a json response).

The first function seems to run 3-5x faster in IE and FF, as I would expect
it to.

Is there a cleaner way to write the first function to get the same
functionality but be more readable?

--
Matt Krusehttp://www.JavascriptToolbox.comhttp://www.AjaxToolbox.com
Hm, that's a mess. I don't know if this is any cleaner:

function func1() {
var o=document, i=0, ps = ['forms', 0, 'elements', 'sel', 'options',
0, 'value'];
while (o=o[ps[i++]]);
return (i == ps.length);
}

Seems a little obfuscated to me, but it's something to ponder.

-David

Feb 16 '07 #2

P: n/a
On Feb 16, 12:11 pm, "David Golightly" <davig...@gmail.comwrote:
On Feb 16, 6:35 am, "Matt Kruse" <newsgro...@mattkruse.comwrote:
Consider the following two functions:
function func1() {
var o ;
if ( (o=document.forms)
&& (o=o[0])
&& (o=o.elements)
&& (o=o.sel)
&& (o=o.options)
&& (o=o[0])
&& (o=o.value)
) {
return true;
}
return false;
}
function func2() {
if (document.forms
&& document.forms[0]
&& document.forms[0].elements
&& document.forms[0].elements.sel
&& document.forms[0].elements.sel.options
&& document.forms[0].elements.sel.options[0]
&& document.forms[0].elements.sel.options[0].value)
{
return true;
}
return false;
}
The perform the same function of making sure that the entire object chain
exists before trying to reference the "deep" object. This may not be a
perfect example, but in some cases it is definitely necessary to validate
all the way down the object chain that things exist how you expect them to
(for example, a json response).
The first function seems to run 3-5x faster in IE and FF, as I would expect
it to.
Is there a cleaner way to write the first function to get the same
functionality but be more readable?
--
Matt Krusehttp://www.JavascriptToolbox.comhttp://www.AjaxToolbox.com

Hm, that's a mess. I don't know if this is any cleaner:

function func1() {
var o=document, i=0, ps = ['forms', 0, 'elements', 'sel', 'options',
0, 'value'];
while (o=o[ps[i++]]);
return (i == ps.length);

}

Seems a little obfuscated to me, but it's something to ponder.

-David
What about this?

var testDeep = function (o) {
o = o || window;
for ( var i = 1, a = arguments.length; i < a; i ++ ) {
if ( ! (arguments[i] in o) ) {
return undefined;
}
o = o[arguments[i]];
}
return o;
};

testDeep(document,'forms', 0, 'elements', 'sel', 'options', 0,
'value');

Returns document.forms[0].elements.sel.options[0].value, if it exists.

While I haven't tested it, I'd suspect that this function or any other
like it will perform slower than your single if with multiple
assignment expressions.

--i

Feb 17 '07 #3

P: n/a
On Feb 16, 4:26 pm, "Isaac Schlueter" <isaacschlue...@gmail.com>
wrote:
On Feb 16, 12:11 pm, "David Golightly" <davig...@gmail.comwrote:
On Feb 16, 6:35 am, "Matt Kruse" <newsgro...@mattkruse.comwrote:
Consider the following two functions:
<..>
>
What about this?

var testDeep = function (o) {
o = o || window;
Not so good as seen from here. Just guessing, but did you perhaps
intend:

var testDeep = function () {
o = arguments[0] || window;

....
testDeep(document,'forms', 0, 'elements', 'sel', 'options', 0, 'value');

../rh

Feb 17 '07 #4

P: n/a
On Feb 16, 7:13 pm, ron.h.h...@gmail.com wrote:
On Feb 16, 4:26 pm, "Isaac Schlueter" <isaacschlue...@gmail.com>
wrote:
var testDeep = function (o) {
o = o || window;

Not so good as seen from here. Just guessing, but did you perhaps
intend:

var testDeep = function () {
o = arguments[0] || window;
6 of one, half-dozen of the other. These two are functionally
equivalent:

function(x) { alert(x); }
function() { alert(arguments[0]; }

The only difference between your suggestion and mine is that yours
slips "o" into the global scope, because you forgot the "var".
Tsk tsk :P

--i

Feb 17 '07 #5

P: n/a
On Feb 16, 7:28 pm, "Isaac Schlueter" <isaacschlue...@gmail.com>
wrote:
On Feb 16, 7:13 pm, ron.h.h...@gmail.com wrote:
On Feb 16, 4:26 pm, "Isaac Schlueter" <isaacschlue...@gmail.com>
wrote:
var testDeep = function (o) {
o = o || window;
Not so good as seen from here. Just guessing, but did you perhaps
intend:
var testDeep = function () {
o = arguments[0] || window;

6 of one, half-dozen of the other. These two are functionally
equivalent:

function(x) { alert(x); }
function() { alert(arguments[0]; }

The only difference between your suggestion and mine is that yours
slips "o" into the global scope, because <..>
Not quite so. Your iteration starts at "1" which means that you'll
miss "document", thereby returning a value based on whether "o" was
passed. Tsk tsk :P

In either case, if "window" gets selected, it turns into something of
a "deep test" of whether you're in a browser environment, because
there's nothing to take you beyond "window".
>you forgot the "var".
Tsk tsk :P
Accepted with appropriate chagrin :)

../rh

Feb 17 '07 #6

P: n/a
David Golightly wrote:
function func1() {
var o=document, i=0, ps = ['forms', 0, 'elements', 'sel', 'options',
0, 'value'];
while (o=o[ps[i++]]);
return (i == ps.length);
}
Seems a little obfuscated to me, but it's something to ponder.
Definitely. Using your loop structure, I got to this:

var exists = (function(){
var regex = /\[["']?([^"'\]]+)["']?\]/g;
return function(obj) {
var o=window,i=0;
obj = obj.replace(regex,".$1").split('.');
while (o=o[obj[i++]]);
return (i == obj.length+1);
}
})();
exists("document.forms[0].elements['sel'].options[0].value");

The regex could be improved (I believe it will fail on forms['name[]']) but
overall it's an improvement, and generalized!

Thanks.

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com
Feb 17 '07 #7

P: n/a
On Feb 16, 8:52 pm, "Matt Kruse" <newsgro...@mattkruse.comwrote:
David Golightly wrote:
function func1() {
var o=document, i=0, ps = ['forms', 0, 'elements', 'sel', 'options',
0, 'value'];
while (o=o[ps[i++]]);
return (i == ps.length);
}
Seems a little obfuscated to me, but it's something to ponder.

Definitely. Using your loop structure, I got to this:

var exists = (function(){
var regex = /\[["']?([^"'\]]+)["']?\]/g;
return function(obj) {
var o=window,i=0;
obj = obj.replace(regex,".$1").split('.');
while (o=o[obj[i++]]);
return (i == obj.length+1);
}})();

exists("document.forms[0].elements['sel'].options[0].value");

The regex could be improved (I believe it will fail on forms['name[]']) but
overall it's an improvement, and generalized!
Here's an example of an alternative regex you can try:

text.match(/[a-z]+|\d+|"[^"]+"|'[^']+'/gi)

It should turn your string into an ordered array of accessors.

By the way, is "value" correct, or should it be "text"? IE's option
element doesn't have a "value" property.

../rh
Feb 17 '07 #8

P: n/a
ro********@gmail.com wrote:
By the way, is "value" correct, or should it be "text"? IE's option
element doesn't have a "value" property.
Of course it does! How else would you get the value?

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com
Feb 17 '07 #9

P: n/a
On Feb 17, 6:05 am, "Matt Kruse" <newsgro...@mattkruse.comwrote:
ron.h.h...@gmail.com wrote:
By the way, is "value" correct, or should it be "text"? IE's option
element doesn't have a "value" property.

Of course it does! How else would you get the value?
That would be a good point!

It has a value property, and the "value" property has a value that is
not "undefined" provided one assigns a value e.g. in the HTML ...
which I had neglected to do :(. IE doesn't default the "value" to the
"text" value in that case but it seems that FF and Opera do.

I think I've paged in <selectnow, but some HTML remediation may
still be required :).

../rh
Feb 17 '07 #10

P: n/a
ro********@gmail.com said the following on 2/17/2007 11:28 AM:
On Feb 17, 6:05 am, "Matt Kruse" <newsgro...@mattkruse.comwrote:
>ron.h.h...@gmail.com wrote:
>>By the way, is "value" correct, or should it be "text"? IE's option
element doesn't have a "value" property.
Of course it does! How else would you get the value?

That would be a good point!

It has a value property, and the "value" property has a value that is
not "undefined" provided one assigns a value e.g. in the HTML ...
which I had neglected to do :(. IE doesn't default the "value" to the
"text" value in that case but it seems that FF and Opera do.

I think I've paged in <selectnow, but some HTML remediation may
still be required :).
<URL:
http://groups.google.com/group/comp....029b734629d5c5
>
Enjoy :)

--
Randy
Chance Favors The Prepared Mind
comp.lang.javascript FAQ - http://jibbering.com/faq/index.html
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Feb 17 '07 #11

P: n/a
On Feb 16, 8:52 pm, "Matt Kruse" <newsgro...@mattkruse.comwrote:
David Golightly wrote:
function func1() {
var o=document, i=0, ps = ['forms', 0, 'elements', 'sel', 'options',
0, 'value'];
while (o=o[ps[i++]]);
return (i == ps.length);
}
Seems a little obfuscated to me, but it's something to ponder.

Definitely. Using your loop structure, I got to this:

var exists = (function(){
var regex = /\[["']?([^"'\]]+)["']?\]/g;
return function(obj) {
var o=window,i=0;
obj = obj.replace(regex,".$1").split('.');
while (o=o[obj[i++]]);
return (i == obj.length+1);
}})();

exists("document.forms[0].elements['sel'].options[0].value");

The regex could be improved (I believe it will fail on forms['name[]']) but
overall it's an improvement, and generalized!

Thanks.

--
Matt Krusehttp://www.JavascriptToolbox.comhttp://www.AjaxToolbox.com
Hm, what's wrong with

var value;
try {
value = document.forms[0].elements['sel'].options[0].value;
} catch (ex) {
// value remains undefined
}

if (typeof(value) != 'undefined') {
// blah blah blah
}

inline, instead of using a function? Guaranteed to be quicker, and
since your function just returns a boolean value, it'll give the same
result...

-David

Feb 18 '07 #12

P: n/a
David Golightly wrote:
Hm, what's wrong with
var value;
try {
value = document.forms[0].elements['sel'].options[0].value;
} catch (ex) {
// value remains undefined
}
Will unnecessarily fail in any browser not implementing try/catch.

To generalize it, you need to pass in the object string and eval() it, which
in my tests causes it to run about the same speed as my previous function.

--
Matt Kruse
http://www.JavascriptToolbox.com
http://www.AjaxToolbox.com
Feb 18 '07 #13

P: n/a
VK
On Feb 18, 7:46 pm, "Matt Kruse" <newsgro...@mattkruse.comwrote:
David Golightly wrote:
Hm, what's wrong with
var value;
try {
value = document.forms[0].elements['sel'].options[0].value;
} catch (ex) {
// value remains undefined
}
Bingo! This is as the fastest and the most reliable one to use for
many years in the row already. I skept on the "glory" to remind it
exactly because I knew in advance the criticism template. At least
because it was Golightly and not VK we avoided derragatory terms in
response.
Will unnecessarily fail in any browser not implementing try/catch.
Which are?
Oh, sorry, I've forgotten the plot again: "it doesn't matter that
there are not any to care of - but theoretically there can be some
day".
To generalize it, you need to pass in the object string and eval() it, which
in my tests causes it to run about the same speed as my previous function.
That is not technically possible. JScript/JavaScript doesn't cache
dispid's but re-retrieves them over and over again even within the
same block. This is why your way was times quicker than the old-
fashioned "step-by-step nesting". For the same reason try-catch will
be times quicker than your own way. It does not imply of course try-
catch exclusively: the pure productivity is rarely the only
consideration to care about.

Feb 18 '07 #14

P: n/a
David Golightly wrote:
<snip>
Hm, what's wrong with

var value;
try {
value = document.forms[0].elements['sel'].options[0].value;
} catch (ex) {
// value remains undefined
}

if (typeof(value) != 'undefined') {
// blah blah blah
}
<snip>

Three things may be raised as objections. The first is that try-catch was
introduced into the language an ECMA 262, 3rd Ed. and is not
back-compatible with previous versions. Fortunately the last few years
have seen pre-3rd edition implementations virtually disappear so that
objection is probably no longer significant.

However, in general try-catch is not particularly useful in javascript
because it can only catch all exceptions, in contrast to the hierarchical
exception handling in, for example, Java. This results in code that
either handles all exceptions identically (which will be inappropriate in
many cases, and may conceal programming errors (say you spell 'forms'
wrongly; you never see the exception and may find it hard to see why the
function never goes into the 'blah blah blah' branch regardless of the
input (while seeing a "document.froms has no properties" error would give
the game away first time))) or that tests the nature of each exception
and re-throws the ones that it cannot handle. The latter suffers from the
very considerable variation in exceptions thrown in differing
environments and so the considerable effort required in picking up all
the variations of the ones that can be handled.

The next objection would be the software design principle that you do not
use an error handling mechanism for program flow control. Whether that
objection applies to this example is questionable. I think it probably
comes down on the right side using error handling for flow control.

Finally there is the principle for defensive programming where you do not
provoke the throwing of an exception where you can test for the
conditions that might result in the throwing of the exception. Obviously
here the exception generating condition can be tested for, as that is the
subject of this thread. The advantage of that approach is that if an
exception is thrown then it is not the expected exception, and so
probably signifies something that needs additional attention.

Richard.

Feb 18 '07 #15

P: n/a
VK
On Feb 18, 10:20 pm, "Richard Cornford" <Rich...@litotes.demon.co.uk>
wrote:
The first is that try-catch was
introduced into the language an ECMA 262, 3rd Ed. and is not
back-compatible with previous versions. Fortunately the last few years
have seen pre-3rd edition implementations virtually disappear so that
objection is probably no longer significant.
Wow! I mean like... wow!

:-)

Feb 18 '07 #16

This discussion thread is closed

Replies have been disabled for this discussion.