Tuesday, February 23, 2010

Java Writing functions


General syntax

Functions group together script code; control structures, operations, method calls, etc. in the same way as a normal script. These functions can then be called when needed, and the code contained within them will be run. This makes it very easy to reuse code without having to repeat it within your script.

Functions are defined using one of these constructs:
Normal function construct

function nameOfFunction(listOfVariableNames) {
  function code should be written here
}
Anonymous function, assigned to a variable
Using this syntax for object methods in early Netscape 4 versions will cause problems with the 'this' keyword due to bugs. 

nameOfFunction = function (listOfVariableNames) {
  function code should be written here
};
 
Normal function construct, assigned to a variable
 
nameOfFunction = function anotherNameForTheFunction
(listOfVariableNames)
 {function code should be written here
};

Note : that in this particular case, because the function is being assigned, and not defined normally, the name anotherNameForTheFunction can be used by the code inside the function to refer to the function itself, but the code outside the function cannot see it at all (note that some browsers, mainly Internet Explorer, do not implement this correctly, so you should not rely on it - it is better to use arguments.callee as shown below).

The Function class constructor

functionName = new Function
("function code should be written here");
 
This construct evaluates the code as a string, and is much slower than assigning anonymous functions. It should only be used in places where it is actually needed.

The Function class constructor with parameters

functionName = new Function
("varName","varName2","etc.","function code");

Functions are called using one of these: 

- nameOfFunction(listOfVariables); 
- window.nameOfFunction(listOfVariables); 
- object.onEventName = nameOfFunction;

When created using the normal function construct, the definition does not have to appear at the start of the script (though it is usually best to do so for the sake of clarity). It can even be defined after the the code that calls it. In most cases, no matter where you choose to define your function, the JavaScript engine will create the function at the start of the current scope.

Note : that you should never create a function using the normal function construct inside an 'if' statement (or any equivalent control structure):

if( someCondition ) {
  function functionName() {
    ...this will not work in most browsers...
  }
}

This is permitted by Mozilla's JavaScript 1.5, but this conflicts with ECMAScript 3, the core language used by JavaScript 1.5. As a result, Mozilla based browsers allow it, and most others do not (they will always evaluate the function, even if the condition evaluates to false). It is best not to rely on either behaviour, and do not try to declare functions in this way. Declaring functions inside these statements is possible in all current browsers using assigned anonymous functions, and this is the correct way to achieve the desired effect:

var functionName;
if( someCondition ) {
  functionName = function () {
    ...
  };
}



Using the return statement

The return statement causes a function to stop executing at that point. The code that called the function will still continue to execute.

function doWhatever() {
  var apod = Math.pow(3,7);
  return;
  //the following code will not be executed,
  //no matter what
  apod *= 34;
  if( 700 * 3 <= apod ) {
    return;
    //return on its own is more usually
    //used as part of a conditional
  } else {
    window.alert('The script has made a mistake');
  }
}

The following is an example of using the return statement to return a variable from a function:

function appendComment(passvar) {
  //in this case, I have passed a string variable and I return
  //a string variable. I could return any variable type I want.
  passvar += ' without your help';
  return passvar;
}

var myString = appendComment('I did it');
//myString is now 'I did it without your help'
  
Note that if you need your code to work in older browsers, it is important to make sure that if the return statement is used to return a value, you must ensure that in all cases, the function returns a value, or some Netscape 4 versions will produce errors.

Take, for example, the action of fading. I want to write the same thing repeatedly, slowly fading from one colour to another. Rather than having to calculate this manually, I want to run some script that calculates the fade for me. The script will run nicely as part of a function, where the function returns the next colour at each step, which I can then use. This is useful, because I can then use the same function to produce a variation of the same effect later on, based on different parameters.

function fadeColour( fromcol, tocol, fadePortion ) {
  //in the format fadeColour( 'ff0098', 'fe0934', 0.23 )
  var oF = [], oT = [], oP = [];
  var oH = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
  //get the red, green and blue substrings ...
  for( var x = 0; x < 3; x++ ) {
    //... and convert them from hex into decimal ...
    oF[x] = eval( '0x' + fromcol.substring( 2 * x, ( 2 * x ) + 2 ) );
    oT[x] = eval( '0x' + tocol.substring( 2 * x, ( 2 * x ) + 2 ) );
    //... add on the required portion of difference between the two ...
    oP[x] = Math.round( oF[x] + ( ( oT[x] - oF[x] ) * fadePortion ) );
    //... and convert it back into hex ...
    oP[x] = oH[ ( oP[x] - ( oP[x] % 16 ) ) / 16 ] + oH[ oP[x] % 16 ];
  }
  //... and put them back together again as a colour string
  return '#' + oP.join('');
}

for( var y = 0; y < 10; y++ ) {
  //in 10 steps, fade the colour - also see the section on writing with script
  document.write( '<span style="color:' + fadeColour( 'd2cbff', '000099', y / 9 ) +
  ';">Fade!<\/span> ' );
}

for( var y = 0; y < 12; y++ ) {
  //in 12 steps, fade the colour
  document.write( '<span style="color:' + fadeColour( 'ff0000', '000000', y / 11 ) +
  ';">Fade!<\/span> ' );
}
Fade! Fade! Fade! Fade! Fade! Fade! Fade! Fade! Fade! Fade!
Fade! Fade! Fade! Fade! Fade! Fade! Fade! Fade! Fade! Fade! Fade! Fade!

Warning, if you are returning a value from a function, do not call the function directly from the <a href= method to activate it, or many browsers will (correctly) create a new page containing the returned value as the page content. You can still use return; on its own. You can only return values if you call the function script from another piece of script (like another function). 

If you need to call the function using the <a href= method, use the void operator.
Note, returning false for many events will cancel the action. As an example, if a user submits a form, returning false will cause the form not to be submitted. The exception is onmouseover, where returning true will stop the mouseover from having any effect (such as with a link, where returning true will stop the link url from being displayed in the status bar).


Variable scope
Variable scope is one of the very useful features of languages like JavaScript, so even though it may seem a little complicated, it is worth taking the time to learn how it works.

In a basic script, there may be any number of variables and functions. Take the following example:

var a = 1, b = 2, c = 3;
function sample() {
  var d;
  a = 7;
}
sample();
alert(a);
 
The variables a, b and c are not inside any function when they are declared, so they are in a scope called the global scope. They are available anywhere. Code anywhere else in the script, including inside the sample function, has access to them. The sample function is also global, since it is not inside any other functions. If any other piece of code changes the contents of those variables, then every other part of the code now sees the new contents. As a result, the alert here will show '7', since the value held by the global variable is changed when the function is run.

Variable d is defined inside the sample function, so it is not global. It is in the local scope of the function. What that means is that only the code inside the function can see it. Code outside the function does not even know it exists. This happens with any function. They have the ability to create their own scopes, and their own local variables, without them interfering with variables located in the global scope. Variable names written in the brackets of the function definition are also created as variables in the local scope (and the same applies to the arguments collection):

function sample(myvar) {
  //myvar is now a variable in the local scope
  alert(myvar);
}
sample('hello');

Now try this modification to the earlier code:
 
var a = 1, b = 2, c = 3;
function sample() {
  var a, d;
  a = 7;
}
sample();
alert(a); 
 
Here, the variable a is redefined inside the function. 
Because it is declared using the var keyword, it becomes a local 
instance of a variable. Even though it shares the same name 
as a global variable,the two are completely independent. 
The changes made to that variable inside the function only affect
the local variable, not the global one.As a result, 
the alert will show '1', and not '7'.
 
Now imagine that the code inside the function wants to reference 
the global variable 'a' instead of the local one.The global scope 
is special. In JavaScript, the global scope can be referenced 
using the name 'window'. The code inside the function can 
use window.a to reference the global 'a' variable.Incidentally,
this is why methods like alert can be called using either alert 
or window.alert, since these methods are globally available
(unless they are overwritten in the current scope, of course). 

Nested functions

It is possible to create functions inside other functions. Simply declare another function inside the code of an existing function:
var a = 1, b = 2, c = 3;
function sample() {
  var a, d, e;
  function anothersample() {
    var e, f;
  }
  anothersample();
}
sample();


In that example, the anothersample function only exists inside the sample function, and it can only be called by the code inside the sample function. Code outside that function does not even know it exists. The scopes are also nested, so the code inside the anothersample function has access to b and c from the global scope, a and d from the sample scope, and then e and f from its own local scope. It can also use window.a to reference the variable a from the global scope.

Of course, if you assign a reference to the nested function to a global variable, then the function can be accessed globally through that variable. There is not much point in doing that here, but it becomes very useful when creating object methods (these will be covered in detail in a later chapter).

Scopes have memory

Scopes are actually very clever, since they persist over time. Imagine that the code inside a function creates a local variable. It also creates an event handler function that will be triggered when the user clicks a link:

function sample() {
  var a = 20;
  document.links[0].onclick = function () {
    alert(a);
  };
}
sample();

The action that calls the event handler (inner) function happens much later, a long time after the script that created it has finished running. However, the variable 'a' has survived, so the alert will display the number 20.


Using scope to prevent conflicts


Imagine that you are running a script that uses many global variable and function names. You want to put another script on the same page, but there is a chance that the two scripts will use the same variable names as each other, and may conflict. It is easy to workaround this problem by putting the code from each script inside a function, and running the function. That way, the local scope provided by the function will protect the variables overwriting each other in the global scope. Note that when doing this, it is very important that you remember to declare your variables properly.

The easy way to do this without creating a global function is to create an anonymous function, and enclosing it in parenthesis (internally, the engine will then replace that entire construct with the function reference). You can then use the open-close parenthesis to run it immediately. This construct may look a little odd, but it works:

(function () {
  //Put your script code in here
})();

0 komentar: