Check if key is defined in associative array

M

Michael Winter

[snip]
Reading the article below, (linked to from Cornford's site) I'm curious
if there is ever a time when a Javascript programmer needs to know
anything about the Activation object? Has there ever been a time when
you yourself have needed to use your knowledge of it in any way?

Yes, as it explains some of the behaviour you will observe...
Can I ignore this bit?

....but you probably can get away with ignoring some of the detail, at
least to start with.

Probably the most important bit of information is what the
activation/variable object holds:

- The formal (named) arguments for the function.
- The arguments object.
- Local variables.
- Inner functions defined with

function identifer(...) {...}

or

var identifier = function(...) {...};

In the latter case: an expression assigned to a local variable.

with the most significant being the last item: inner functions. Why? Well,
consider this (admittedly bad) example:

function MyObject() {
/* Define an inner function. Will become
* a property of the activation object.
*/
function myInner() {
return this;
}

/* Define method for the new object. Will
* become a property of that object.
*/
this.myMethod = function() {
return this;
};

/* A test method. It will return an
* object containing two properties:
*
* inner - the result of a call to myInner
* outer - the result of a call to myMethod
*/
this.test = function() {
return {
inner : myInner(),
outer : this.myMethod()
};
};
}

var myObject = new MyObject(),
result = myObject.test();

alert(result.outer == myObject); // true
alert(result.inner == myObject); // false

Notice that although both functions return the this operator, only the
method, myMethod, actually returns a reference to the object, myObject.
The reason is when a function is called, the caller provides the value of
the this operator based on *how* that function is called.

If a method is called as a method:

obj.method()

then the this operator will refer to object (obj, above). However, if a
method is called as a property of the global object (a global function),
or as a property of an activation object (an inner function), then the
this operator will refer to the global object. So, if you go back to the
last line in the example and change it to:

alert(result.inner == window); // or == this);

the message will show true.

I hope that made sense. It seemed a little awkward to explain.

The final point to remember about the activation object is that when a
closure is formed, whether it refers to local variables or functions, or
not, the entire activation object (in fact the entire scope chain) and all
of its properties will be kept in memory. This can be important because if
these properties reference other objects, those objects won't be
considered "collectable" by the garbage collector so you'll keep them in
memory, too. Therefore, it's a good idea to destroy any references you
won't need:

ref = null;

This is also covered in the article, but I thought I'd give it a quick
mention here.

[snip]

If I did a poor job of explaining anything above, even if you understood
my point, do tell me. I'll either have another crack at it (if you want me
to), or I'll try to remember for any future explanations.

Mike
 
L

lkrubner

I just got Danny Goodman's Javascript Bible and it seems to be a good
resource. One thing it seems Javascript lacks (compared to, say, Java)
is a single site that brings together all the DOM information a
programmer might want. Instead, each browser has its own DOM site.
Books about PHP tend to be redundant as they only repeat the info
www.php.net, but Javascript is a language that really needs 3rd - party
efforts at organizing all the language information.
 
L

Laurent Bugnion

Hi,

I just got Danny Goodman's Javascript Bible and it seems to be a good
resource. One thing it seems Javascript lacks (compared to, say, Java)
is a single site that brings together all the DOM information a
programmer might want. Instead, each browser has its own DOM site.
Books about PHP tend to be redundant as they only repeat the info
www.php.net, but Javascript is a language that really needs 3rd - party
efforts at organizing all the language information.

The thing is, the DOM has really nothing to do with JavaScript, and the
DOM is different in each browser, thus a different documentation. Let me
explain.

1) The DOM has nothing to do with JavaScript: The DOM is a set of
objects (Document Object Model) which allows access to the document.
It's an API, an interface. The fact that you program it with JavaScript
is just because JavaScript is available in browsers. In .NET, you
program the DOM of XML files, with C#, VB.NET, JScript, J#, etc... In
IE, you can use VBScript. So you must decide if you want a JavaScript
guide, describing the language, or a DOM documentation, describing the
objects (and if possible, language independant).

2) The DOM is different in each browser: Yeah, unfortunately, each
browser maker has his own implementation, and they differ. These last
days, we're lucky enough that they don't differ that much, but they do.
Thus one documentation per browser (or environment, or platform, if you
like).

The Java documentation you refer to is not a Java documentation stricto
sensu, it's rather the API documentation of the JVM (a platform). There
is only one, because there is only one API, the one released by Sun. In
fact, there are more, because IE used to have their own implementation,
and their own documentation...

I hope it helps you to understand what you're looking for...

Greetings,

Laurent
 
L

lkrubner

I'm assuming it is allowed to use the hash-like syntax to recreate the
effects of a hash table, so long as one remembers that one is not
really dealing with a hash table. I'm trying to come up with a function
that will toggle the visibility for all the DIVs on a page. I need an
object to rememeber the different visibility. Is what I do below an
acceptable use of the hash table type syntax?




isDivVisible = new Object();
function hideOrShowDiv(elementPointer) {
var divId = elementPointer.id;
if (document.getElementById(divId)) {
var optionDiv = document.getElementById(divId);

// 12-30-04 - we need isDivVisible to remember a
different
// visibility state for each div on the page, so we
use
// Javascript's hash-like syntax to keep track of
each
// div as if the various states were being stored
in an array
if (isDivVisible.divId) {
if (isDivVisible["divId"] == true) {
optionDiv.style.visibility='hidden';
optionDiv.style.height='0px';
optionDiv.style.width='0px';
optionDiv.style.overflow='auto';
optionDiv.style.display='none';
isDivVisible["divId"] = false;
} else {
optionDiv.style.visibility='visible';
optionDiv.style.height='auto';
optionDiv.style.width='auto';
optionDiv.style.overflow='auto';
optionDiv.style.display='block';
isDivVisible["divId"] = true;

}
} else {
optionDiv.style.visibility='visible';
optionDiv.style.height='auto';
optionDiv.style.width='auto';
optionDiv.style.overflow='auto';
optionDiv.style.display='block';
isDivVisible["divId"] = true;
}
}
}
 
M

Michael Winter

Please quote relevant material when you reply to a post. I have no idea
what you're replying to.
I'm assuming it is allowed to use the hash-like syntax to recreate the
effects of a hash table, so long as one remembers that one is not really
dealing with a hash table.

Yes. The important thing is to understand and remember the limitations. If
those limitations don't apply then there's no reason to go through the
hassle of implementing a proper hash table.

[snip]
Is what I do below an acceptable use of the hash table type syntax?

Almost, though it could be made a little more robust, however the specific
syntax you use is wrong. You also seem to be performing some unnecessary
element reference -> id -> element reference operations again.
isDivVisible = new Object();

I don't like the name, isDivVisible. Names like that (ones which contain
'is' or 'has') should be reserved for functions because they "answer"
questions by returning a value. Variables don't "do" anything.
function hideOrShowDiv(elementPointer) {

By 'elementPointer', I assume you mean a reference[1] to a HTML element.
var divId = elementPointer.id;
if (document.getElementById(divId)) {
var optionDiv = document.getElementById(divId);

If you passed a reference to the function, why are you getting the id and
then the reference again? You did this once before - I would have hoped
you'd remember not to do it again.
// 12-30-04 - we need isDivVisible to remember a
different
// visibility state for each div on the page, so we
use
// Javascript's hash-like syntax to keep track of
each
// div as if the various states were being stored
in an array

It's best to make sure that code posted to a newsgroup can be copied
without alteration. With comments like the one above, I'd suggest you use
a multiline (/*...*/) comment rather than several single line ones.

Assuming the line below did what you intended it to...
if (isDivVisible.divId) {

The else block for the inner if..else statement below will never be
executed. Think about it: the (incorrect) expression above doesn't
determine whether the property is defined, just whether it evaluates to
true or false. The sort of test you're looking for is a typeof analysis.

Killing two birds with one stone:

if('boolean' == typeof isDivVisible[divId]) {

Notice that you were using 'divId' literally, rather than the value it
contained. As for the typeof test, this makes more sense: if you defined
the property yourself, it will either be true or false (a boolean). If the
property is defined, but it's not a boolean, then the property was
predefined (by the object's prototype).
if (isDivVisible["divId"] == true) {
optionDiv.style.visibility='hidden';
optionDiv.style.height='0px';
optionDiv.style.width='0px';
optionDiv.style.overflow='auto';
optionDiv.style.display='none';

This is excessive. If you're trying to hide an element and collapse the
space it occupies, just use the display property.
isDivVisible["divId"] = false;
} else {
optionDiv.style.visibility='visible';
optionDiv.style.height='auto';
optionDiv.style.width='auto';
optionDiv.style.overflow='auto';
optionDiv.style.display='block';

Assuming that the page stylesheet doesn't hide any DIV elements initially,
you could simply assign an empty string to the display property to restore
the DIV.
isDivVisible["divId"] = true;

[snip]

Overall, the script could be condensed to:

var divs = {};

function toggleDiv(ref) {var id = ref.id, value = divs[id];
if(!ref.style) {return;}
if('boolean' == typeof value) {
/* If the DIV is visible, set the display property to 'none'. */
ref.style.display = value ? 'none' : 'block';
/* Toggle the value in the hash table. */
divs[id] = !value;
} else {
/* What you do here depends on what you'd expect if the entry
* in the hash table was undefined. If the DIV would be hidden
* then you could use:
*/
divs[id] = false;
toggleDiv(ref);
}
}

Depending on what is actually happening in your page, you could make this
a lot easier.

In the simplest case, the display property is only set in one of two ways:
via the style attribute on the element itself, or the style object. In
other words, the display cannot be affected through a class or some other
mechanism in a page style sheet. Assuming you meet this criteria, you
could inspect the style object itself, rather than use an object to
contain the state of each DIV:

function toggleDiv(ref) {
if((ref = ref.style)) {
ref.display = ('none' == ref.display) ? '' : 'none';
}
}

On the other hand, if you're in a more complicated situation, then you can
obtain the computed value of the display property. It's pretty much the
same as the above except determining the current value is a little more
difficult (especially as IE requires its own code path).

function getComputedStyle(obj) {var dV = document.defaultView;
if(!obj || ('object' != typeof obj)) {return null;}
return(getComputedStyle = (dV && dV.getComputedStyle) ?
function(obj) {return dV.getComputedStyle(obj, null);}
: ((dV = null) || obj.currentStyle) ?
function(obj) {return obj.currentStyle;}
: function() {return null;})(obj);
}

function toggleDiv(ref) {var cS;
if((cS = getComputedStyle(ref)) && (ref = ref.style)) {
ref.display = ('none' == cS.display) ? 'block' : 'none';
}
}

(Untested)

Hope that helps,
Mike


[1] There are no pointers in ECMAScript, only references, despite what
Microsoft's documentation might suggest.
 
C

Chris Riesbeck

Michael Winter said:
I don't like the name, isDivVisible. Names like that (ones which contain
'is' or 'has') should be reserved for functions because they "answer"
questions by returning a value. Variables don't "do" anything.

I'm with you, but then how do you name boolean variables, like
a "trace" flag, so that

if (booleanVar) {

reads clearly?
 
M

Michael Winter

[...] how do you name boolean variables, like a "trace" flag, so that

if (booleanVar) {

reads clearly?

It would depend on the purpose. Certainly for most variables, the
adjective itself (like visible) should suffice. I'm terrible at thinking
of things on the spot though, so I can't currently come up with an
exception. Perhaps you can think of a troublesome name.

Mike
 

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

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top