Sign in to follow this  
tstrimp

[web] It's official, I hate JS

Recommended Posts

tstrimp    1798
I'm having problems accessing an associative array in javascript using a variable. Something that should be simple is driving me crazy! Any google searches I do simply return information on javascript associative arrays which never seem to have the information I'm looking for. Anyway, here is the problem.
function Sample(ID)
{
	alert(ID);  // Displays 'test';
	myObjArray[ID].DisplaySomething();  // Gives error 'Error: myObjArray[ID] has no properties'
	myObjArray["test"].DisplaySomething();  // Does what it is supposed to.
}

Sample("test");


Obviously ID contains the string 'test'. Obviously myObjArray["test"].DisplaySomething() works. Why wont myObjArray[ID].DisplaySomething() work!!! Any help would be greatly appreciated.

Share this post


Link to post
Share on other sites
markr    1692
Should work.

Try posting complete source and/or URL of page showing code not working.

Make sure that the thing you think is a string, really is the string you think it is and doesn't contain whitespace, case differences, or invisible unicode characters (zero-width non-joiner and its friends). In javascript (like most programming languages really), strings are only equal if they consist of precisely the same characters in the same order. Even characters which look identical or invisible characters will change them.

Mark

Share this post


Link to post
Share on other sites
tstrimp    1798
Ok, here is the entire file. This is pretty much my first time writing javascript (Sad I know but I'm more of a server side kinda guy).


var MenuControl = new Array();

function Menu(BaseObj, MenuID)
{
this.MenuID = MenuID;

MenuObj = document.getElementById(MenuID);
MenuObj.style.visibility = 'visible';

MenuObj.onmouseout = DelayClose(MenuID);
BaseObj.onmouseout = DelayClose(MenuID);
MenuObj.onmouseover = StopClose(MenuID);
BaseObj.onmouseover = StopClose(MenuID);

CloseHandle = false;
DelayTime = 300;
}


Menu.prototype.Shout = function()
{
// Just testing MenuControl array.
alert(this.MenuID);
}


function StopClose(MenuID)
{
if(MenuControl[MenuID].CloseHandle != false)
{
clearTimeout(this.CloseHandle);
}
}


Menu.prototype.CloseMenu = function()
{
this.MenuObj.style.visibility = 'hidden';
}


function DelayClose(MenuID)
{
alert(MenuID);
MenuControl[MenuID].Shout();
MenuControl["TopMenu"].Shout();
// The above is for testing, here is what it is really supposed to do.
//MenuControl[MenuID].CloseHandle = setTimeout(MenuControl[MenuID].CloseMenu(), MenuControl[MenuID].DelayTime);
}


function OpenMenu(BaseObj, MenuID)
{
MenuControl[MenuID] = new Menu(BaseObj, MenuID);
}






Basicly a link has an onmouseover event that calls OpenMenu. From there everything should be handled by the js. It sets the onmouseout and onmouseover events to delay hide the element and to cancel the hide respectively. The problem is when I move the mouse out and DelayClose is called. The first alert shows the ID of the div like it should but MenuControl[MenuID].Shout(); doesn't work but the next one does. Hopefully this all makes sense.

Share this post


Link to post
Share on other sites
markr    1692
There are a number of obvious problems with this. javascript is a clever, but somewhat strange language, that obviously doesn't do quite what you expect.

In your Menu constructor function,

MenuObj.onmouseout = DelayClose(MenuID);


You do know what this does, right?

This IMMEDIATELY calls the function DelayClose(MenuID) and then sets the onmouseout property of MenuObj to that. This is probably not what you want.

onmouseout is a property which is expected to be a function, not the return value from DelayClose (which doesn't return anything anyway).

Perhaps what you meant was


MenuObj.onmouseout = function () { DelayClose(MenuID); };


This uses the "closures" feature, which means that MenuID (which is in scope at the time), will still be in scope when the anonymous function defined above is called (and will still have the right value, regardless of how many Menu objects are instatiated with different IDs).

There are several other problems in your code. I suggest that you do something a bit simpler first, to understand

- How javascript has first class function objects
- What "this" does in javascript (which is not always obvious) - "this" is set to the object the method is called off, which is not necessarily the one you expect.

In javascript, functions are objects.


var x = somefunction(); // calls somefunction() and places result in x


is entirely different from


var x = somefunction; // Makes x the same as somefunction (does not call it)


You are confusing the two.

Also, in javascript, functions can take functions as parameters and/or return functions - which makes it more like a functional language.

You just hate JS because you don't understand it. Once you do, you will learn to love it :)

Mark

Share this post


Link to post
Share on other sites
tstrimp    1798
Quote:
Original post by markr
There are a number of obvious problems with this. javascript is a clever, but somewhat strange language, that obviously doesn't do quite what you expect.

In your Menu constructor function,

MenuObj.onmouseout = DelayClose(MenuID);




I think the main problem I have with the language is the lack of a good reference. I saw the onmouseout used in another script and thought it took a callback function of some sort (They didn't have the () at the end.) however no amount of searching involving javascript and onmouseout would tell me anything about setting the onmouseout property in a function.


Quote:
onmouseout is a property which is expected to be a function, not the return value from DelayClose (which doesn't return anything anyway).


I figured that. Thats why I was hoping it would run that function [wink].

Quote:

Perhaps what you meant was


MenuObj.onmouseout = function () { DelayClose(MenuID); };


This uses the "closures" feature, which means that MenuID (which is in scope at the time), will still be in scope when the anonymous function defined above is called (and will still have the right value, regardless of how many Menu objects are instatiated with different IDs).


Perfect! Should be exactly what I'm looking for. The problem is, however, delayclose WAS being called on mouseout. The first and third alert in the function fired correctly. The second one (the one I wanted to work) didn't.

Quote:
There are several other problems in your code. I suggest that you do something a bit simpler first, to understand

- How javascript has first class function objects
- What "this" does in javascript (which is not always obvious) - "this" is set to the object the method is called off, which is not necessarily the one you expect.

In javascript, functions are objects.


I realized that while working on my 1st attempt at creating this little project with a more oop approach. I didn't like how it was turning out (I currently hate the JS idea of an object) so I changed much of it back to procedural code. Most of the .this stuff was taken out. I believe the only case I use .this in the one I posted was in the prototype for Shout which according to the "OOP in javascript" pages I read is how you add a member function to an "Object" in js. Shouldn't that have worked fine?

Quote:


var x = somefunction(); // calls somefunction() and places result in x


is entirely different from


var x = somefunction; // Makes x the same as somefunction (does not call it)


You are confusing the two.


heh. If you want to be technical I wasn't confusing the two because I didn't realize there was a difference [wink]. How then do you set an object that has some constructor parameters?


var x = function () {somefunction(a, b, c)};


Quote:

Also, in javascript, functions can take functions as parameters and/or return functions - which makes it more like a functional language.


I think I'll like that once I get some of the semantecs out of the way. Overall I think I'll have to blame my crappy coding on all the JS coders out there who like to write code as obfuscated as possible! Don't they know what whitespace is?! Thanks for the advice I appreciate it a lot!

Quote:

You just hate JS because you don't understand it. Once you do, you will learn to love it :)

Mark


I hope so. I don't venture out into the world of client side scripting very often but I'd like to be much more productive when it does happen. I just wish browsers (IE) would conform to some sort of standard so that you don't have to write browser specific code!

Share this post


Link to post
Share on other sites
Fuzztrek    572
Quote:
How then do you set an object that has some constructor parameters?


var x = new somefunction(a, b, c);


In javascript, functions can also be classes. If you wanted to define methods of somefunction, you would use the this keyword:
this.Shout = function() { alert(this.myVar); }

Note that you can also define functions outside of your "class" function and reference them like this:
this.Shout = externalFunction;

Note the lack of parenthesis. It generally makes more sense to use the former.

Now you can use:
x.Shout();

or
alert(x.myVar);

which does the same thing.

edit: You can also prototype functions, as you did in your examples above. I usually only use them when modifying objects native to the language (like Array, String, etc)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this