Q. What are the different ways to invoke a function? What would the implicit reference "this" refer to? A. The functions can be invoked via one of the following 5 ways
|
So, why use function_name.call(...) or function_name.apply( ... ) as opposed to just function_name( ... )? Lets look at this with some examples.
var x = 1; //global variable x;
var obj1 = {x:3}; //obj1 variable x
var obj2 = {x:9}; //obj2 variable x
function function_name(message) {
alert(message + this.x) ;
}
function_name("The number is "); //alerts the global x --> The number is 1
//the first argument is the obj reference on which to invoke the function, and the
//the second argument is the argument to the function call
function_name.call(obj1, "The number is "); //alerts the obj1s x --> The number is 3
function_name.call(obj2, "The number is "); //alerts the obj2s x --> The number is 5
//the first argument is the obj reference on which to invoke the function, and
//the second argument is the argument to the function call as an array
function_name.apply(obj1, ["The number is "]); //alerts the obj1s x --> The number is 3
function_name.apply(obj2, ["The number is "]); //alerts the obj2s x --> The number is 5
The purpose is of call and apply methods are to invoke the function for any object without being bound to an instance of the this object. In the above example, the this object is the global object with the x value of 1. In a function called directly without an explicit owner object, like
function_name()
, causes the value of this
to be the default object (window
in the browser). The call and apply methods allow you to pass your own object to be used as the "this" reference. In the above example, the obj1 and obj2 were used as "this" reference.Q. What will be the alerted message for buttons 1-5 shown below?
The test.html stored under js_tutorial/html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form id="someform">
<input id="btn1" type="button" value="click-me1"/>
<input id="btn2" type="button" value="click-me2"/>
<input id="btn3" type="button" value="click-me3" onclick="buttonClicked()"/>
<input id="btn4" type="button" value="click-me4"/>
<input id="btn5" type="button" value="click-me5"/>
</form>
<script language="javascript" type="text/javascript" src="../js/test.js">
</script>
</body>
</html>
The test.js stored under js_tutorial/js.
function buttonClicked(){
var text = (this === window) ? window : this.id;
alert( text );
}
var button1 = document.getElementById(btn1);
var button2 = document.getElementById(btn2);
var button4 = document.getElementById(btn4);
var button5 = document.getElementById(btn5);
button1.onclick = this.buttonClicked; //or just button1.onclick = buttonClicked;
button2.onclick = function(){
buttonClicked();
};
button4.onclick = function(){
buttonClicked.call(button4);
};
button5.onclick = function(){
buttonClicked.apply(button5);
};
A. The "this" object passed to the buttonClicked function are as follows:
click-me1 --> btn1 ("btn1" because its a method invocation and this will be assigned the owner object - the button input element)
click-me2 --> window (This is the same thing as when we assign the event handler directly in the elements tag as in click-me3 button)
click-me3 --> window (global object)
click-me4 --> btn4
click-me5 --> btn5
When defining event handlers via frameworks like jQuery, the library will take care of overriding the value of "this" reference to ensure that it contains a reference to the source of the event element. For example,
$(#btn1).click( function() {
var text = (this === window) ? window : this.id; //// jQuery ensures this will be the btn1
alert( text );
});
The jQuery makes use of apply( ) and call( ) method calls to achieve this.
Q. What will be the output for the following code snippet?
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form id="someform">
<input id="btn1" type="button" value="click-me1" onclick="test()"/>
</form>
<script language="javascript" type="text/javascript" src="../js/test2.js">
</script>
</body>
</html>
the test2.js file.
var myobj1 = {
x:9,
myfunction:function(){
if(this === window)
alert("x is not Defined");
else if (this === myobj1)
alert(this.x);
else
alert("Error!");
}
}
function test(){
setTimeout(myobj1.myfunction, 1000);
}
A. The output in the alert will be "x is not defined". This is because the "this" will be referring to the default global object -- window. The above code can be fixed by replacing the test() function as shown below.
function test(){
setTimeout(function(){
myobj1.myfunction()},
1000);
}
Note: The setTimeout(..,..) method alerts only after 1 second of clicking the button.
Q. What is a callback function? Why would you need callback functions?
A. As mentioned earlier, the functions in JavaScript are actually objects. For example,
var functionAdd = new Function("arg1", "arg2", "return arg1 * arg2;");
functionAdd(5,9); // returns 14
functionAdd(2,3); // returns 5
So, the functions can be passed as arguments to other functions and invoked from other functions. For example,
function functionAdd(arg1, arg2, callback) {
var result = arg1 + arg2
// Since were done, lets call the callback function and pass the result
callback(result);
}
// call the function
functionAdd(5, 15, function(result) {
// this anonymous function will run when the callback is called
console.log("callback called! " + result);
});
Why invoke the callback function when the functionAdd(..) could have executed the results? Client-side is predominantly asynchronous with following types of events.
UI Events like mouse click, on focus, value change, etc. These events are asynchronous because you dont know when a user is going to click on a button. So, callback functions need to be invoked when a button is clicked. For example JavaScript frameworks like jQuery quite often uses callback functions. Whether handling an event, iterating a collection of nodes, animating an image, or applying a dynamic filter, callbacks are used to invoke your custom code at the appropriate time.
The test.js.
$(document).ready(function(){
$("button").click(function(){
$("p").hide(2000,function(){
console.log("Inside the callback function...");
//called 2 seconds after the paragraph is hidden
alert("The paragraph is now hidden");
});
});
});
The test.html
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="test.js"></script>
</head>
<body>
<button>Hide</button>
<p>The praragraph to hide when a button is clicked.</p>
</body>
</html>
Timer functions like setTimeout(function, delay), setInterval(function, delay), etc will delay the execution of a function. For example, you might want to disable a form button after its been clicked to prevent double form submission, but then re-enable it again after a few seconds. The clearTimeout() function then allows you to cancel the callback from occuring if some other action is done which means the timeout is no longer required.
Another reason why these timers are useful is for some repetitive tasks some milliseconds apartment. The reason why the timers are used instead of a simply while (true) { ... } loop is because Javascript is a single-threaded language. So if you tie up the interpreter by executing one piece of code over and over, nothing else in the browser gets a chance to run. So, these timers allow other queued up events or functions to be executed.
Invoke myObj1.myObj1.myMethod() after 1 second.
var myObj1 = {
myVar:12,
myMethod:function(){
alert(this.x || "Not defined") ; // "Not defined" is the default if x is not defined
}
}
setTimeout(function(){myObj1.myMethod()}, 1000);
Ajax calls are made asynchronously and when a response is received from the server, a callback method is invoked to process the response. The Ajax calls do have the following states
AJAX states:
0: The request is uninitialized (before youve called open()).
1: The request is set up, but not sent (before youve called send()).
2: The request was sent and is in process (you can usually get content headers from the response at this point).
3: The request is in process; often some partial data is available from the response, but the server isnt finished with its response.
4: The response is complete; you can get the servers response and use it.
So, you want the callback function to be invoked when the state == 4. Lets look at an example.
Here is the test2.html
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script language="javascript" type="text/javascript" src="ajax.js">
</script>
<title>Insert title here</title>
</head>
<body>
</body>
</html>
The ajax.js.
function processAjaxRequest(url, callback) {
var httpRequest; // create our XMLHttpRequest object
if (window.XMLHttpRequest) {
//For most browsers
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) {
//For IE
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
//onreadystatechange event registers an anonymous (i.e. no name) function
httpRequest.onreadystatechange = function() {
// this is called on every state change
if (httpRequest.readyState === 4) {
callback.call(httpRequest.responseXML); // call the callback function
}
};
httpRequest.open(GET, url);
httpRequest.send();
}
processAjaxRequest ("http://localhost:8000/simple", function() {
console.log("Executing callaback function....");
console.log("1.This will be printed when the ajax response is complete. "); //LINE A
});
console.log("2. This will be printed before the above console.log in LINE A."); //LINE B
Note: If you use FireFox, you can vie the console via Tools --> Web Developer --> Web Console. When you run the above example, check the web console output.
Now, for the purpse of learning JavaScript, Ajax, etc, you can create your own HTTP server with a quick and dirty approach as shown below. The Java 6, has a built in non-public API for HTTP. This approach should not be used in real life.
The Java HTTP Server
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class SimpleJavaHTTPServer {
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/simple", new MyHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
static class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
String response = "<ajax-xml>some text</ajax-xml>";
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
}
The LINE B will be printed before LINEA.
Note: If you run the above Java code within Java 6 or later, you will get an ajax response of <ajax-xml>some text</ajax-xml> when you invoke http://localhost:8000/simple. You may get a "restricted API" in eclipse IDE, you could overcome this by removing and adding the rt.jar via the build path or you could try the following from the preferences menu go into Java --> Compiler --> Errors/Warnings --> Depricated and Restricted API and change the "forbidden reference" from "Error" to "Warning".