Javascript - Useful Tips & Tricks

That’s fine if you are starting from scratch and have a complete overview of what’s meant to be going on at all times, or if you don’t mind amending the HTML code throughout your site.

If you just want to be sure that whatever you or anyone else has done/may do in the future you aren’t going to break it you can do this:


var uniqueNameOldOnload = ( window.onload ) ? window.onload : false ;

window.onload = function()
	{
	if ( uniqueNameOnload ) uniqueNameOnload() ;
...
	}

The only point where you have to be careful is making sure that every time you do this you use a different variable name for the previously existing window.onload function. Otherwise you get into an infinite regress.

You can avoid name conflicts in JavaScript by using anonymous functions.


// Let's assume this is the old code you can't change:
window.onload = function() {
    alert("First onload function");
};

(function() {
    var old_onload = this.onload;

    this.onload = function(evt) {
	// If there was a previous onload function, call it.
	if (old_onload)
	    old_onload(evt);

	// Do whatever you'd like to do in your onload function here.
	alert("Second onload function");

	// Allow the JS engine to garbage collect this functions.
	self.onload = null;
    };
})();

I used ‘window’, ‘self’ and ‘this’ in this example just to demonstrate several ways to get at the global object.

Is there any way of calling off Javascript without entering the whole script into the html? I’ve tried a simple <script src=“./js.js”>, however it never seems to work.

Cool thread…definatly bookmarking this one…

real shame that it doesn’t validate in XHTML 1.0 (Strict)
it would help me a lot having language=“Javascript 1.x”
to also hide things like regex

helped alot- everything on the page

My object-oriented version of parsing the query string:

/* usage example:
//assuming location.search = '?n1=v1&n2=v2&n3=v3'
var qs = new QueryString(location.search);
alert(qs);	//outputs ?n1=v1&n2=v2&n3=v3
alert(qs.string);	//outputs ?n1=v1&n2=v2&n3=v3 (quicker than toString() since it's direct property access)
alert(qs.length);
alert(qs.n1);	//outputs v1
alert(qs.n2);	//outputs v2
alert(qs.n3);	//outputs v3
for (var i = 0; i < qs.length; i++) {
	alert(qs[i]);	//outputs <name>=<value>
	alert(qs[i].name);	//outputs <name>
	alert(qs[i].value);	//outputs <value>
}
*/
window.QueryString = function(str) {
	this.string = str;	//this.string is faster than this.toString()
	this.length = 0;
	var re = /[?&]([^\\s=]+)=([^\\s&]*)/g;
	var match = re.exec(str);
	while (match) {
		var name = match[1];
		var value = decodeURI(match[2]);
		this[name] = value;
		this[this.length] = new QueryString.Pair(name, value);
		this.length++;
		match = re.exec(str);
	}
}

QueryString.prototype.toString = function() {
	return this.string;
}

QueryString.Pair = function(name, value) {
	this.name = name;
	this.value = value;
}

QueryString.Pair.prototype.toString = function() {
	return this.name + '=' + this.value;
}

Some random esoteric notes on Javascript and DOM perks, performance, bugs, and compatibility. Some info might be somewhat outdated, so use the info at your own risk.

EDIT: moved this to my own semi-temporary website: maian.50webs.com

Ha! My school teaching grounds :slight_smile:

Instead of writing:


<script type="text/javascript">
var text = "The meeting this week will be at ";
  var nowDate = new Date();
  var currDate = nowDate.getDate();

switch(currDate) {
  case 1:
  case 2:
  case 3:
  case 4:
    document.write(text + "Steve's house");
    break;
  case 5:
  case 6:
  case 7:
  case 8:
  case 9:
  case 10:
  case 11:
    document.write(text + "Nancy's house");
    break;
  case 12:
  case 13:
  case 14:
  case 15:
  case 16:
  case 17:
  case 18:
    document.write(text + "Mike's house");
    break;
  default:
    document.write(text + "Sally's house");
    break;
  }
</script>

You can write it like this:


<script type="text/javascript">
var text = "The meeting this week will be at ";
  var nowDate = new Date();
  var currDate = nowDate.getDate();
  [color=royalblue]switch(true)[/color] {
  case (currDate < 5) && (currDate > 0):
    document.write(text + "Steve's house");
    break;
  case (currDate < 12) && (currDate > 4):
    document.write(text + "Nancy's house");
    break;
  case (currDate < 19) && (currDate > 11):
    document.write(text + "Mike's house");
    break;
  default:
    document.write(text + "Sally's house");
    break;
  }
</script>

eval() can be replaced by window in alot of cases.


<script type="text/javascript">
var a="alert"
var b="hi"
eval(a+"(\\""+b+"\\")")
window[a]([b])

</script>

Only when making object references that descend from the window object.

What you’re really trying to point out is that bracket-notation is the better choice for member access.

Yeah that too, eval() is known to lock up system resources.
Instead of making a function like this, which I see people making all the time:


function getEl(id){
if(document.getElementById)
return document.getElementById(id)
else if(document.all)
return eval("document.all."+id)
else if(document.layers)
return eval("document."+id)
else return null
}

Avoid eval() by doing this:


function getEl(id){
if(document.getElementById)
return document.getElementById(id)
else if(document.all)
return [color=royalblue]document.all[id][/color]
else if(document.layers)
return [color=royalblue]document[id][/color]
else return null
}

But If you were going to make such a function in the first place, do it right:


if(!document.getElementById){

if(document.all)document.getElementById=function(){
if(typeof document.all[arguments[0]]!="undefined")return document.all[arguments[0]];else return null
}
else if(document.layers)document.getElementById=function(){
if(typeof document[arguments[0]]!="undefined")return document[arguments[0]];else return null
}

}

//This code was programmed by me, Ultimater

window can replace eval() when refering to global variables too:


<script type="text/javascript">
var my_message="hello world"
var a_var="my_message"
alert(eval(a_var))
alert(window[a_var])
</script>

Why is arguments[0] better than the name of the first argument?

It’s a more generic way of referring to the first argument.
A lot of times you later change the name of your argument as you enhance your function and forget to change crucial code inside the function that uses the old name.

Believe it or not I even needed to edit my last post because I first called the argument el then decided later to call it id because it is a string and not an element. Thus, I left one instance of the old name floating in my code and had to edit my post.

Just for the record,
arguments[0] can always be used to refer to the first argument whether or not you named the argument.
When you assign a name for an argument, I’d assume the function runs a minute(a bit) slower because there are now two variables able to access the same thing.
Which before there was only one – arguments[0].
Thus, it’s an extra statement assigns your name to the argument.

Both ways are correct, and the choice is up to you.

But that is not the main idea I’m trying to get across.

The reason why my last code is better (than my other two example functions) is because it only defines the document.getElementById function if it’s undefined – which occurs when the user is using an old browser.

If the user is indeed using an old browser, my last code still runs faster (than my other two example functions) because it performs all of it’s document.all and document.layer if-checks only once – to define the document.getElementById function rather than each time the function is run.

Also, notice how my function is able to return null if no such object is found – just like the real document.getElementById function.

Some Uncommon Information about Math.random:
Math.random returns a random number greater than or equal to zero but smaller than and excluding one. Therefore it is possible for it to return an actual zero but not a one
(which is very unlikely, the odds are about one in ten quadrillion[10^16]).
Source: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
(15.8.2.14 PDF page 128)

Furthermore, when mixing Math.round and Math.random, be cautious. The following may seem like it produces random numbers but the odds of getting certain numbers are amazingly sliced in half!:


alert(Math.round(Math.random()*3))

In the above statement, the chances of getting a zero or three are cut in half!
(because it’s range is from 0 through 3)

Math.random()*3
0.0 - 0.49 rounds to a 0
0.5 - 1.49 rounds to a 1
1.5 - 2.49 rounds to a 2
2.5 - 3.00 rounds to a 3

Here is a safe way to mix the two:


alert(Math.round(  (Math.random()*3)-0.5  ))

(Note: if Math.random returns a zero, the above will alert a zero)

I’d strongly suggest using Math.floor in place of Math.round.

Math.floor is basicly a function that always brings the number to the floor or rounds down.
Math.ceil is basicly a function that always addes a ceiling to the number or rounds up.

Safe Math.floor alternitive:


alert(Math.floor( Math.random()*4) )

Unsafe Math.ceil alternitive:


alert(Math.ceil( Math.random()*4)-1 )

Can’t use the above because it can return a -1 if Math.random returns an exact 0.

Here’s my mighty new Math.random function:


function safeRand(){
var r=Math.random();
if(r==0){return safeRand()}
return r;
}

Now let’s put the two together:

Safe Math.ceil alternitive:


function safeRand(){
var r=Math.random();
if(r==0){return safeRand()}
return r;
}
alert(Math.ceil( safeRand()*4)-1 )

Labelled statements, break, and continue

These are actually features of any C-style language. Any statement can be labelled, and continue and break statements can target them:

outer: for (var i = 0; i < 5; i++)
  for (var j = 0; j < 10; j++) {
    document.write('[' + i + ','+ j + ']');
    if (j == 1)
      break outer;
  }

As that example shows, the |break outer;| ends execution of the whole loop. This example outputs: [0,0][0,1]

outer: for (var i = 0; i < 5; i++)
  for (var j = 0; j < 10; j++) {
    document.write('[' + i + ','+ j + ']');
    if (j == 1)
      continue outer;
  }

In this example, the |continue outer;| skips the rest of the current iteration and goes to the next iteration of the loop. This example outputs: [0,0][0,1][1,0][1,1][2,0][2,1][3,0][3,1][4,0][4,1]

Break and continue statements can only target labels they are nested in. That means they can’t be used as a generic goto statement. For example,

label: some_statement;
//...
break label;

wouldn’t work.

Labelled statements and break, revisited

The above are pretty well-known features. Now comes the interesting part.

label: if (cond) {
  for (var i = 0; i < 10; i++)
    if (obj[i] == [/i]null)
      break label;
  alert('obj has no null elements');
}

That would work exactly how’d you expect it to work. That’s right - any statement can be a label, and breaks can target them in the same way. The only differences are:

[list=1][]The continue statement can’t be used here - continue statements can only be used on loops.
[
]The breaks must have label targets - it must be |break label;| instead of just |break;|. |break;| would only work in loops.[/list]

That’s not all. There’s another statement that can be used to abstract this break to label functionality to anything: the block statement, i.e. |{ … }|.

label: {
  for (var i = 0; i < 10; i++)
    if (obj[i] == [/i]null)
      break label;
  alert('obj has no null elements');
}

That’s the same as the above, except without the |if|. This means there’s no need for weird hacks like this:

label: do {
  if (cond1)
    break label;
  statement1;
  statement2;
  statement3;
  statement4;
  if (cond2)
    break label;
  statement5;
  statement6;
} while (0);

or equivalently:

if (cond2) {
  statement1;
  statement2;
  statement3;
  statement4;
} else if (!cond1) {
  statement1;
  statement2;
  statement3;
  statement4;
  statement5;
  statement6;
}

They can be replaced with:

label: {
  if (cond1)
    break label;
  statement1;
  statement2;
  statement3;
  statement4;
  if (cond2)
    break label;
  statement5;
  statement6;
}

A note on block statements

Unlike C/C++, the block statement in JS does not introduce a new scope. For example, in C++:

int a = 1;
{
  int a = 2;
  cout << a;
}
cout << a;

would output: 12.

The equivalent in JS (in the HTML environment):

var a = 1;
{
  var a = 2;
  document.write(a);
}
document.write(a);

would output: 22. That means, that the inner a and the outer a are actually the same thing. To illustrate the point further:

{
  int a = 1;
  cout << a;
}
cout << a;

would be a syntax error in C++, while the equivalent in JS:

{
  var a = 1;
  document.write(a);
}
document.write(a);

would output: 11.

All about the OR and AND operators

A simple OR example that would alert “true” is:


<script type="text/javascript">
alert(true||false)
//alerts "true"
</script>

Now what most people don’t know is that the following actually alerts “first stuff” rather than “true”:


<script type="text/javascript">
alert("first stuff"||"second stuff")
//alerts "first stuff"
</script>

The reason for that is because anything that isn’t 0, false, or null is treated as though it were “true” and the OR operator isn’t limited to returning either true or false like most operators are (it can return “first stuff” in my example). Also the OR operator first “looks at” the first argument and checks if the first argument is true or false then only if the first argument is false does the OR operator ever look at the second argument. In otherwords meaning if the first argument is true then it doesn’t matter if the second argument is true or false because either way the OR operator only needs one true in order to return true (really the first argument). Only if two falses are found does the OR operator return false (really the second argument)


<script type="text/javascript">
function a1s(){alert("function a1s() has been called");return true}
function a2s(){alert("function a2s() has been called");return true}
if(a1s()||a2s())alert(true)

//alerts "function a1s() has been called"
//alerts "true"
</script>


<script type="text/javascript">
if("first stuff")alert("true")
//alerts "true"
</script>

The following will alert “second stuff”:


<script type="text/javascript">
alert(false||"second stuff")
//alerts "second stuff"
</script>

Let’s go a bit further:


<script type="text/javascript">
var v1="first stuff"
var v2="second stuff"
if(v1){
var v3=v1
}
else{
v3=v2
}
alert(v3)
//alerts "first stuff"
</script>

Some fancy foot-work:


<script type="text/javascript">
var v1="first stuff"
var v2="second stuff"
var v3=(v1)?v1:v2
alert(v3)
//alerts "first stuff"
</script>

And the grand finale:


<script type="text/javascript">
var v1="first stuff"
var v2="second stuff"
var v3=v1||v2
alert(v3)
//alerts "first stuff"
</script>

Also don’t confuse the OR operator(||) with the Bitwise OR-operator(|):


<script type="text/javascript">
alert(3516|1354)
//alerts "3582"
</script>

You are probably thinking, “How in the world does that alert 3582!?”
Here’s an explaination:
3516 in Binary is 110110111100
1354 in Binary is 010101001010

110110111100
010101001010


110111111110

110111111110 in Decimal is 3582

Might as well teach you the bitwise AND operator now lol. Don’t confuse the AND operator(&&) with the Bitwise-AND operator(&).


<script type="text/javascript">
alert(3516&1354)
//alerts "1288"
</script>

Here’s an explaination:
3516 in Binary is 110110111100
1354 in Binary is 010101001010

110110111100
010101001010


010100001000

010100001000 in decimal is 1288

Finally, similar to the OR operator, the AND operator doesn’t need to “look at” both arguments either:


<script type="text/javascript">
function a1s(){alert("function a1s() has been called");return false}
function a2s(){alert("function a2s() has been called");return false}
if(a1s()&&a2s())alert(true)
else alert(false)
//alerts "function a1s() has been called"
//alerts "false"
</script>

In order for the AND operator to return true (really the second argument), it needs both arguments to be true otherwise it returns false (really the second argument).

And the Grand Finale Finale lol:


<script type="text/javascript">
alert("first stuff"&&"second stuff")//alerts "second stuff"
alert("first stuff"||"second stuff")//alerts "first stuff"
</script>

Sorry for miss-calling my grand finales.

Here are some tips concerning the syntax of javascript code. It is not a “must do”, but it will make your code easier to read for others.

First of all, always put a semicolon ( ; ) at the end of a line where it is needed, so on every line which does not contain an if-else-end, for, while or switch-case structure. Also, put every new command on a new line, so don’t heap up a lot of code on the same line.

Now for the brackets. A lot of people use C-style brackets, meaning that the opening bracket is on the same line as the if() command. Although this might seem professional, it does not help to make your code easy to understand. Propose that you want to remove an if() command, you should then also remove the matching bracket. But when you put the opening bracket on the same line as the if(), it is not easy to spot which closing bracket to remove. You should also always use brackets after an if() command, also if only one command will follow after it:

Wrong example:

if (argument1 != argument2) {
	dosomething(); andsomethingelse()
	if (a1 == b2) {
		return blaat();
	} else {
		if (sdf == fsd)
			return test();
	}
}

Good example

if (argument1 != argument2)
{
	dosomething();
	andsomethingelse();

	if (a1 == b2)
	{
		return blaat();
	}
	else
	{
		if (sdf == fsd)
		{
			return test();
		}
	}
}

Please note that I also put the brackets in front of and after “else” on a new line. When you want to remove an if statement now, you can easily spot all other code which needs to be adjusted.

Another thing which a lot of people do clumsy, is commenting their code. If you place comments, always place them above the line you actually want to tell something about. Do not put your comments at the end of a line, even if they are tiny ones. Also, when you have a big block of code (like a user defined function), you do not need to comment every line, just make sure the code itself works like it should, and only tell what the function returns and how you should use it.

// Function which does difficult things, returns a
// string with details about the user (or something :P)
// Needs no parameters
function example_function()
{
	//big block of code here
	//big block of code here
	//big block of code here
	//big block of code here
	//big block of code here
	//big block of code here
	//big block of code here
	return "You are running a browser!";
}

// This example code will call a function and return it to the user
var strVariable;

strVariable = example_function();
window.alert(strVariable);

As long as you make sure no bugs are in the functions, that’s all the user needs to know… :slight_smile:

I hope someone can take advantages with these tips. For the comments, most of the times you will still remember why and how you did something, but if other people need to use the same code, it is nice if they can use it right away, without them having to read it four times… :slight_smile: