[web] It's official, I hate JS

Started by
4 comments, last by Fuzztrek 18 years, 9 months ago
I'm having problems accessing an associative array in &#106avascript using a variable. Something that should be simple is driving me crazy! Any google searches I do simply return information on &#106avascript associative arrays which never seem to have the information I'm looking for. Anyway, here is the problem. <!--STARTSCRIPT--><!--source lang="cpp"--><div class="source"><pre> function Sample(ID) { alert(ID); <span class="cpp-comment">// Displays 'test';</span> myObjArray[ID].DisplaySomething(); <span class="cpp-comment">// Gives error 'Error: myObjArray[ID] has no properties'</span> myObjArray[<span class="cpp-literal">"test"</span>].DisplaySomething(); <span class="cpp-comment">// Does what it is supposed to.</span> } Sample(<span class="cpp-literal">"test"</span>); </pre></div><!--ENDSCRIPT--> Obviously ID contains the string 'test'. Obviously myObjArray["test"].DisplaySomething() works. Why wont myObjArray[ID].DisplaySomething() work!!! Any help would be greatly appreciated.
Advertisement
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 &#106avascript (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
Ok, here is the entire file. This is pretty much my first time writing &#106avascript (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.
There are a number of obvious problems with this. &#106avascript 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 &#106avascript has first class function objects<br>- What "this" does in &#106avascript (which is not always obvious) - "this" is set to the object the method is called off, which is not necessarily the &#111;ne you expect.<br><br>In &#106avascript, functions are objects.<br><br><pre><br>var x = somefunction(); // calls somefunction() and places result in x<br></pre><br><br>is entirely different from<br><br><pre><br>var x = somefunction; // Makes x the same as somefunction (does not call it)<br></pre><br><br>You are confusing the two.<br><br>Also, in &#106avascript, functions can take functions as parameters and/or return functions - which makes it more like a functional language.<br><br>You just hate JS because you don't understand it. &#79;nce you do, you will learn to love it :)<br><br>Mark
Quote:Original post by markr
There are a number of obvious problems with this. &#106avascript 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 &#106avascript and &#111;nmouseout would tell me anything about setting the &#111;nmouseout property in a function.<br><br><br><!--QUOTE--><BLOCKQUOTE><span class="smallfont">Quote:</span><table border=0 cellpadding=4 cellspacing=0 width="95%"><tr><td class=quote><!--/QUOTE--><!--STARTQUOTE-->onmouseout is a property which is expected to be a function, not the return value from DelayClose (which doesn't return anything anyway).<!--QUOTE--></td></tr></table></BLOCKQUOTE><!--/QUOTE--><!--ENDQUOTE--><br><br>I figured that. Thats why I was hoping it would run that function [wink].<br><br><!--QUOTE--><BLOCKQUOTE><span class="smallfont">Quote:</span><table border=0 cellpadding=4 cellspacing=0 width="95%"><tr><td class=quote><!--/QUOTE--><!--STARTQUOTE--><br>Perhaps what you meant was<br><br><pre><br> MenuObj.onmouseout = function () { DelayClose(MenuID); };<br></pre><br><br>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).<br><!--QUOTE--></td></tr></table></BLOCKQUOTE><!--/QUOTE--><!--ENDQUOTE--><br><br>Perfect! Should be exactly what I'm looking for. The problem is, however, delayclose WAS being called &#111;n mouseout. The first and third alert in the function fired correctly. The second &#111;ne (the &#111;ne I wanted to work) didn't.<br><br><!--QUOTE--><BLOCKQUOTE><span class="smallfont">Quote:</span><table border=0 cellpadding=4 cellspacing=0 width="95%"><tr><td class=quote><!--/QUOTE--><!--STARTQUOTE-->There are several other problems in your code. I suggest that you do something a bit simpler first, to understand <br><br>- How &#106avascript has first class function objects<br>- What "this" does in &#106avascript (which is not always obvious) - "this" is set to the object the method is called off, which is not necessarily the &#111;ne you expect.<br><br>In &#106avascript, functions are objects.<br><!--QUOTE--></td></tr></table></BLOCKQUOTE><!--/QUOTE--><!--ENDQUOTE--><br><br>I realized that while working &#111;n 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 &#111;nly case I use .this in the &#111;ne I posted was in the prototype for Shout which according to the "OOP in &#106avascript" pages I read is how you add a member function to an "Object" in js. Shouldn't that have worked fine? <br><br><!--QUOTE--><BLOCKQUOTE><span class="smallfont">Quote:</span><table border=0 cellpadding=4 cellspacing=0 width="95%"><tr><td class=quote><!--/QUOTE--><!--STARTQUOTE--><br><pre><br>var x = somefunction(); // calls somefunction() and places result in x<br></pre><br><br>is entirely different from<br><br><pre><br>var x = somefunction; // Makes x the same as somefunction (does not call it)<br></pre><br><br>You are confusing the two.<br><!--QUOTE--></td></tr></table></BLOCKQUOTE><!--/QUOTE--><!--ENDQUOTE--><br><br>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?<br><br><pre><br>var x = function () {somefunction(a, b, c)};<br></pre><br><br><!--QUOTE--><BLOCKQUOTE><span class="smallfont">Quote:</span><table border=0 cellpadding=4 cellspacing=0 width="95%"><tr><td class=quote><!--/QUOTE--><!--STARTQUOTE--><br>Also, in &#106avascript, functions can take functions as parameters and/or return functions - which makes it more like a functional language.<br><!--QUOTE--></td></tr></table></BLOCKQUOTE><!--/QUOTE--><!--ENDQUOTE--><br><br>I think I'll like that &#111;nce I get some of the semantecs out of the way. Overall I think I'll have to blame my crappy coding &#111;n 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!<br><br><!--QUOTE--><BLOCKQUOTE><span class="smallfont">Quote:</span><table border=0 cellpadding=4 cellspacing=0 width="95%"><tr><td class=quote><!--/QUOTE--><!--STARTQUOTE--><br>You just hate JS because you don't understand it. &#79;nce you do, you will learn to love it :)<br><br>Mark<!--QUOTE--></td></tr></table></BLOCKQUOTE><!--/QUOTE--><!--ENDQUOTE--><br><br>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!
Quote:How then do you set an object that has some constructor parameters?


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


In &#106avascript, 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)

This topic is closed to new replies.

Advertisement