Difference between revisions of "JavaScript"

From CSE330 Wiki
Jump to navigationJump to search
 
(108 intermediate revisions by 7 users not shown)
Line 1: Line 1:
= Javascript =
+
JavaScript is the most widely used scripting language for implementing client-side functionality in Web applications, and, in recent years, it's become very popular for server-side application, too.  Unlike PHP, JavaScript code can be interpreted and executed in a client's web browser, instead of on the web server, depending on how it's being used.
You should start by reading the w3schools javascript tutorial, which covers most of the important features of the language:
 
  
http://www.w3schools.com/js/default.asp
+
== JavaScript?  Did you mean Java? ==
  
=Asynchronous JavaScript And XML=
+
'''JavaScript''' is a prototype-based programming language focused on web interactivityIt was first introduced in Netscape Navigator, and it in turn gave rise to what is now '''[http://www.ecmascript.org/ ECMAScript]'''.  Originally, JavaScript was called "LiveScript"Sun, the developer of Java at the time, wanted a language that would complement its compiled Java language, and so LiveScript was renamed JavaScript.
AJAX, Asynchronous Javascript And XML, is a group of related web development techniques, standards, and technologies used on the client (web browser) side of the standard web server-client communication modelAlthough other languages can be used, the most common is to use javascript to send asynchronous requests to the web server in order to retrieve XML data that the javascript then uses to produce dynamic, fast, user-friendly web pagesThe key idea is that most of the work happens at the web browser, keeping waiting times for data to come back over the network to a minimum.
 
  
The javascript ''XMLHttpRequest'' object is used to exchange data with the web servers without needing to reload the entire web page in the browser. This ''XMLHttpRequest'' object is now supported by all major browsers, although some browsers implement support in slightly different ways, leading to different behavior of the same code on different platforms.  For this course, you should focus on supporting Firefox, but in any real production website it's very important to do validation testing using all of the major browsers including Firefox, Internet Explorer, Safari, and Opera as a minimum.
+
Beyond that, '''Java and JavaScript are as similar as Ham and Hamster.'''
  
== XMLHttpRequest Object ==
+
Java and JavaScript have similar syntax, but the under workings are quite different. For example, Java requires strict typing, but JavaScript allows for dynamic typing.  Java is object-oriented, but JavaScript is prototype-oriented.  Java is compiled, but JavaScript is interpreted.  Java supports event listeners, but JavaScript makes them a fundamental part of the language.  Java variables are scoped to the innermost method or loop, but JavaScript variables are scoped only to the innermost function.
  
The ''XMLHttpRequest'' object handles communication with the web servers.  To use it, you must first initialize a variable to be an instance of the ''XMLHttpRequest'' class.
+
== JavaScript Language Components ==
  
  var xmlHttp;
+
This section highlights some features of the JavaScript language that differentiate it from other languages.  For a more comprehensive JavaScript tutorial, the following tutorials are both quality:
  xmlHttp=new XMLHttpRequest();
 
  
Once you have an ''XMLHttpRequest'', you can use it to send requests to a server. Initially, you need to connect to the server side page you are interested in:
+
* [https://developer.mozilla.org/en-US/docs/Web/JavaScript Mozilla Developer Network]: Great for learning JavaScript for the first time.  Advocates best practices for modern JavaScript development.
 +
* [http://www.quirksmode.org/js/contents.html QuirksMode]: More advanced than the Mozilla tutorial, but it thoroughly covers the most powerful aspects of pure JavaScript and gives unparalleled advice on browser compatibility.
  
  xmlHttp.open("METHOD","REMOTE_URL", ASYNCRONOUS_FLAG);
+
Advice: Do '''NOT''' Google for "JavaScript Tutorial". The first few hits advocate bad or outdated practices.  Stick with the ones listed here.
  
where METHOD is "GET" or "POST", REMOTE_URL is the page that you are going to send requests to, and ASYNCRONOUS_FLAG is true or false to indicate whether the calls should be made asynchronously or synchronously. In asynchronous communication, the client can do other things while waiting for the server response, whereas in synchronous communication, the client blocks execution and waits until the response comes back before proceeding.  Once the object has been opened, you can then use the ''send'' method to send a request to the server. Note that you do not explicitly set data fields to send, because it is contained in the URL request.
+
=== Variables and Scope ===
  
xmlHttp.send(null);
+
To define a variable in JavaScript, use the '''let''' keyword.
  
The ''XMLHttpRequest'' object has an attribute, ''readyState'', that stores the current state of the request.
+
<source lang="javascript">
 +
let foo = "bar";
 +
</source>
  
<table class="ex" border="1" width="50%" cellpadding="2" cellspacing="0" id="table7">
+
To define a constant in JavaScript, use the '''const''' keyword.
<tr><th align="left" width="10%">State</th><th align="left">Description</th></tr>
 
<tr><td>0</td><td>The request is not initialized</td></tr>
 
<tr><td>1</td><td>The request has been set up</td></tr>
 
<tr><td>2</td><td>The request has been sent</td></tr>
 
<tr><td>3</td><td>The request is in process</td></tr>
 
<tr><td>4</td><td>The request is complete</td></tr>
 
</table>
 
  
For example, when a request is sent, the state is set to ''2''.  Every time the state changes, javascript automatically calls a function specified by the ''onreadystatechange'' attribute.  So, before calling a remote site, you should setup a new function:
+
<source lang="javascript">
 +
const foo = "bar";
 +
</source>
  
xmlHttp.onreadystatechange=function()
+
'''Note: We should NOT see any variables initialized with var in your code. Some might appear in the linked examples, since those are from older versions of the language so please replace those with let and const in your mind'''
{
+
Var creates ambiguity to anyone reading your code and is becoming deprecated in JavaScript.
  alert('state changed to '+xmlHttp.readyState);
 
}
 
  
This is how asynchronous requests are handled. Once you send a request, you access the response only through the ''onreadystatechange'' function. Meanwhile, your client page can be doing other things. If you are waiting for a response from the server, you should check whether the ''readyState'' is ''4'', corresponding to the request being completed. The server's response is returned as part of the ''XMLHttpRequest' ''responseText'' attribute.  
+
All variables are objects. In the case above, the variable '''foo''' is an object of the class '''String'''.
  
xmlHttp.onreadystatechange=function()
+
Notice that like PHP, you do not have to explicitly define a type for a variable like '''int''' or '''String'''; this is because JavaScript and PHP are ''dynamically typed languages''.
{
 
  if(xmlHttp.readyState==4)
 
  {
 
    .... do some cool stuff ...
 
  }
 
}
 
  
For example, if you have following html file, server.html:
+
JavaScript code can access any variable higher in the “function tree”, but not vice-versa.  This is called '''scope'''.  ''All functions create their own scope.''
  
<code>
+
When you reference a variable, JavaScript will look up through the "function tree" until it finds the variable you asked for.  This means that you could define variables of the same name as global variables inside of functions.  For demonstration of concept:
<pre>
 
hello world
 
</pre>
 
</code>
 
  
This server page just prints the hello world message.
+
<source lang="javascript">
 +
const a = "hello";
 +
const b = "world";
  
Here is an AJAX implementation that gets the message from the server and prints it.
+
function sayGoodByeWorld(){
 +
const a = "goodbye";
  
<code>
+
alert(a); // goodbye
<pre>
+
alert(b); // world
&lt;html>
+
}
&lt;body>
+
 
&lt;script>
+
sayGoodByeWorld();
  var xmlHttp;
+
 
  xmlHttp=new XMLHttpRequest();
+
alert(a); // hello
 +
</source>
 +
 
 +
=== Object Literals ===
  
  xmlHttp.open("GET","server.html",true);
+
A very common way of storing and transporting data in JavaScript is by using objects. You can define an object with certain properties using an '''object literal''':
  
  xmlHttp.onreadystatechange=function()
+
<source lang="javascript">
  {
+
const apple = {
    if(xmlHttp.readyState==4)
+
color: "red",
    {
+
flavor: "sweet",
      var pElement=document.getElementById("msg");
+
season: "autumn"
      pElement.innerHTML=xmlHttp.responseText;
+
}
    }
 
  }
 
  
  xmlHttp.send(null);
+
alert(apple.color); // red
&lt;/script>
+
</source>
&lt;p id="msg">&lt;/p>
 
&lt;/body>
 
&lt;/html>
 
  
</pre>
+
=== Functions ===
</code>
 
  
==Sending Parameters==
+
To define a function in JavaScript, use the '''function''' keyword.
The parameters are sent either in the url (to, for example, a PHP page) or through the ''send'' function.
 
Consider following PHP code that takes two parameters, multiplies them and return the result.
 
  
multiply.php
+
<source lang="javascript">
<code>
+
function sayHello(){
<pre>
+
alert("Hello World");
&lt;? echo $_GET["x"]*$_GET["y"]?>
+
}
</pre>
 
</code>
 
  
We can then use AJAX to get the multiplication of two numbers:
+
sayHello(); // call the function
 +
</source>
  
multiply-ajax.php
+
Pass an argument to a function like this:
<code>
 
<pre>
 
&lt;html>
 
&lt;body>
 
&lt;script>
 
function multiply ()
 
{
 
  var xmlHttp;
 
  xmlHttp=new XMLHttpRequest();
 
  var x,y;
 
  x=document.getElementById("input_x").value;
 
  y=document.getElementById("input_y").value;
 
  xmlHttp.open("GET","multiply.php?x="+x+"&y="+y,true);
 
  
  xmlHttp.onreadystatechange=function()
+
<source lang="javascript">
  {
+
function sayHello(name){
    if(xmlHttp.readyState==4)
+
alert("Hello, "+name);
    {
 
      var pElement=document.getElementById("msg");
 
      pElement.innerHTML=xmlHttp.responseText;
 
    }
 
  }
 
  xmlHttp.send(null);
 
 
}
 
}
&lt;/script>
 
x:&lt;input id="input_x" type="text"/ >&lt;br>
 
y:&lt;input id="input_y" type="text"/>&nbsp;&nbsp;
 
&lt;a href="javascript:multiply();">Multiply&lt;/a>
 
&lt;br>
 
------------------------&lt;/br>
 
Result:
 
&lt;p id="msg">&lt;/p>
 
&lt;/body>
 
&lt;/html>
 
</pre>
 
</code>
 
  
Note that the x and y values are sent as part of the url as GET parameters. You can also send them as part of the ''send'' function, provided that your receiving page uses POST parameters.
+
sayHello("Todd"); // call the function and pass an argument
 +
</source>
 +
 
 +
====Arrow Functions====
 +
The latest versions of JavaScript have introduced arrow functions.  They provide a cleaner syntax for writing functions, and maintain scope when using classes.
 +
 
 +
The general syntax is:
 +
<source lang="javascript">
 +
(param1, param2, ... , paramN) => { statements }
 +
 
 +
//removing the brackets around { statements } is equivalent to
 +
{ return statements; }
 +
 
 +
//No parameters should be 2 empty parentheses as such:
 +
() => { statements }
 +
</source>
 +
 
 +
The example above could be written as follows:
 +
 
 +
<source lang="javascript">
 +
const sayHello = (name) => alert("Hello, "+name);
 +
sayHello("Todd");
 +
</source>
 +
 
 +
Arrow functions can be particularly useful when you're looking to contain function logic within cleanly and compactly. For example, iterating over an array and making updates to each item of the array.
 +
<source lang="javascript">
 +
let arr = [1,2,3,4,5];
 +
let newArr = arr.map(number => number*5); //newArr is an array containing [5,10,15,20,25]
 +
</source>
 +
 
 +
==== Functions are Objects ====
 +
 
 +
In JavaScript, functions are objects.  This means that they can be assigned to variables, manipulated on the fly, and even passed as arguments to other functions!  '''''This is an extremely important feature of JavaScript''''' that makes it such a robust language for web development.
 +
 
 +
You create a function variable like this:
 +
 
 +
<source lang="javascript">
 +
const sayHello = function(){
 +
alert("Hello World");
 +
}
 +
 
 +
sayHello(); // call the function
 +
</source>
 +
 
 +
Observe that you can make [[#Variables and Scope|scope-dependent]] functions in this way.
 +
 
 +
=== Closures ===
 +
 
 +
{{DoctypeTV
 +
|youtube_id=HaPlj796ngQ
 +
|time=5m45s
 +
|desc=JavaScript Closures
 +
}}
 +
 
 +
A '''closure''' is a way to separate a certain snippet of JavaScript code from the global scope.  This is useful if you do not want to "muck up" global variables.  Closures are nothing more than anonymous functions that are called as soon as they are created:
 +
 
 +
<source lang="javascript">
 +
const a = "hello";
 +
 
 +
(​​​​function(){
 +
const b = "world";
 +
 +
alert(a); // hello
 +
alert(b); // world
 +
})();
 +
 
 +
alert(a); // hello
 +
alert(b);​ // ReferenceError: b is not defined​​​​​​​​​​​​​​​
 +
</source>
 +
 
 +
{{JSFiddleExample
 +
|title=Passing Variables to a Closure
 +
|desc=This example demonstrates how you can "save" previous versions of a variable using closures.  This is possible because of scoping and the fact that function variables can be returned as objects.
 +
|fiddle_id=YURqa
 +
}}
 +
 
 +
Most JavaScript libraries (like jQuery) write all of their code in a closure.  What this means is that except for one or two variable names (jQuery or $), everything associated with the library is completely self-contained.
 +
 
 +
=== Prototypal Inheritance ===
 +
 
 +
JavaScript implements '''prototypal inheritance''', as opposed to a language like Java or C++, which implements '''classical inheritance'''.  JavaScript is one of only a handful of languages implementing prototype-based inheritance.
 +
 
 +
Here's how it works.  Every callable object (function) has a '''prototype'''.  When instances of that object are created, their properties and methods are copied (inherited) from the prototype.  Additionally, changes made to the prototype later in the program are "copied" to every instance.
 +
 
 +
For example, if you wanted to make a method on all strings that added a “!”, you could modify String’s prototype:
 +
 
 +
<source lang="javascript">
 +
String.prototype.bang = function(){
 +
return this+"!"; // Notice: the context is the instance itself
 +
}
 +
 
 +
alert("Hello".bang()); // alerts Hello!
 +
</source>
 +
 
 +
To "extend" an object, just copy its prototype to a new object.  However, since classical inheritance and prototypal inheritance are different concepts, copying prototypes may have results that you don't expect.  [http://beej.us/blog/data/javascript-prototypes-inheritance/ This article] seems to have a pretty good explanation of how to "inherit" prototypes with example implementations.
 +
 
 +
==== Extending Built-In Prototypes ====
 +
 
 +
You should be aware that there is an active debate in the web development community about whether it is good programming style to extend the prototypes of built-in objects like String and Array, such as in the ''String.prototype.bang'' example above.  There are legitimate arguments on both sides.  [http://stackoverflow.com/questions/8859828/javascript-what-dangers-are-in-extending-array-prototype This Stack Overflow post] has good links to some articles discussing this issue.
 +
 
 +
=== Context ===
 +
 
 +
{{DoctypeTV
 +
|youtube_id=0a4r4bm1nQA
 +
|time=4m32s
 +
|desc=The ''this'' Variable in JavaScript
 +
}}
 +
 
 +
Every function is called on a certain object, which is not necessarily the same object in which it was defined.  This is called '''context'''.
 +
 
 +
To call a function on an arbitrary context, use either '''call''' or '''apply'''.  ''call'' takes a list of arguments, while ''apply'' takes them all in an array.
 +
 
 +
To access the current context, use the '''this''' keyword.  Demonstration of concept:
 +
 
 +
<source lang="javascript">
 +
const sayThisColor = function(){
 +
alert(this.color);
 +
}
 +
 
 +
const apple = { color: "red" }
 +
 
 +
sayThisColor();  // undefined
 +
sayThisColor.call(apple); // red
 +
</source>
 +
 
 +
== Events ==
 +
 
 +
Events are really what make JavaScript such a powerful language for web development.
 +
 
 +
Rather than being thread based, JavaScript is event based.  Since all JavaScript code runs in a single thread, '''there are no concurrency issues'''.  When an event occurs, JavaScript automatically calls the ''event callback'' as soon as all previous events' callbacks have finished executing.
 +
 
 +
Code in the form of a '''callback function''' is associated with events via a '''listener'''.  For example, the following JavaScript causes ''sayHello()'' (the callback function) to be run whenever the button with ID "hello" is clicked (the event):
 +
 
 +
<source lang="javascript">
 +
const sayHello = function(){
 +
alert("Hello World");
 +
}
 +
 
 +
document.getElementById("hello").addEventListener("click", sayHello, false);
 +
</source>
 +
 
 +
{{JSFiddleExample
 +
|title=Binding Callbacks to a Button Click
 +
|fiddle_id=L8c4Z
 +
|cse330=true
 +
|desc=In this example, notice how we bind the callback function when the ''DOMContentLoaded'' event fires.  This is because JavaScript requires that the button has been parsed by the browser before it can add event listeners to it.
 +
}}
 +
 
 +
The '''addEventListener''' method takes three parameters:
 +
* The event type
 +
* The callback function
 +
*: The callback function is passed one parameter: the event object.
 +
* A boolean representing bubble (false) or capture (true) phase
 +
*: You usually want Bubble phase.  For more information on event phase, see [[#Event Phase]]
 +
 
 +
Note that versions of Internet Explorer prior to version 9 required that you use a different, albeit similar, function for assigning event listeners called '''attachEvent'''.  attachEvent takes the same arguments as addEventListener, except you need to put '''on''' before the event type (e.g. "onclick"), and the third argument (phase) is not necessary.
 +
 
 +
It is perfectly valid to use an '''anonymous function''' as your callback function:
 +
 
 +
<source lang="javascript">
 +
document.getElementById("hello").addEventListener("click", function(event){
 +
alert(`Hello, World!  Event Type: ${event.type}`);
 +
}, false);
 +
</source>
 +
 
 +
QuirksMode has perhaps the best series of articles about the ins and outs of JavaScript events on the internet: http://www.quirksmode.org/js/contents.html#events
 +
 
 +
=== The Event Object ===
 +
 
 +
Callback functions are passed one argument: an ''event object''.  You see above that one property of the event object is ''event.type''.  To see the full list of properties of the event object, you could run the code:
 +
 
 +
<source lang="javascript">
 +
document.getElementById("my_btn").addEventListener("click", function(event){
 +
let strout = "";
 +
for(var i in event){
 +
strout += `${i}: ${event[i]}\n`;
 +
}
 +
console.log(strout);
 +
}, false);
 +
</source>
 +
 
 +
Some of the most useful properties and methods include:
 +
* '''event.target''' references the object on which the event occurred.
 +
* '''event.currentTarget''' references the object whose listener is currently being processed.
 +
*: ''Note:'' event.target and event.currentTarget might be the same or might be different, depending on whether you are listening for bubbled events.
 +
* '''event.preventDefault()''' stops the normal result of the event from being executed.  For example, if you listen for a form's ''submit'' event, you can call event.preventDefault() to stop the form from being submitted.
 +
* '''event.stopPropagation()''' prevents any other event listeners from being executed.  For more detail, read the section on Event Phase below.
 +
 
 +
For more detail on the event object, see [http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html#interface-Event the W3C specification].
 +
 
 +
'''Note:''' If your callback function does not take any parameters, it will still run; you just won't have as easy of access to the event object.
 +
 
 +
=== Event Handlers and Memory Management ===
 +
 
 +
JavaScript is an automatically garbage-collected language, meaning that memory management is mostly taken care of for you.  However, there are some instances when you need to be careful about creating "zombie" objects.  In JavaScript, this mostly revolves around the idea of event listeners.
 +
 
 +
I could give an explanatory example, but instead I'll tell you straightaway that '''the moral of the story is that for every "addEventListener", there should probably be a "removeEventListener".'''  Here are some good articles to satisfy your hunger for more details on event listeners and JavaScript memory management:
 +
 
 +
* http://www.vladalexandruionescu.com/2012/08/javascript-memory-leaks.html
 +
* http://lostechies.com/derickbailey/2012/03/19/backbone-js-and-javascript-garbage-collection/
 +
* http://stackoverflow.com/questions/5326300/garbage-collection-with-node-js
 +
 
 +
When you start working with Node.JS in the next module, it's more important than ever to keep good accounting of your event listeners.
 +
 
 +
=== Event Phase ===
 +
 
 +
In JavaScript, events occur in two phases: '''Capture Phase''' and '''Bubble Phase'''.  Consider the following HTML document:
 +
 
 +
<source lang="html4strict">
 +
<!DOCTYPE html>
 +
<html>
 +
<head><title>Event Test</title></head>
 +
<body>
 +
  <div id="box">
 +
    <button id="btn">
 +
      Hello
 +
    </button>
 +
  </div>
 +
</body>
 +
</html>
 +
</source>
 +
 
 +
Suppose the user clicks on the "Hello" button.  Events will be fired in the following order:
 +
 
 +
# Capture Phase CLICK on the Document
 +
# Capture Phase CLICK on the Body
 +
# Capture Phase CLICK on the Div#box
 +
# Target Phase CLICK on the Button#btn
 +
# Bubble Phase CLICK on the Div#box
 +
# Bubble Phase CLICK on the Body
 +
# Bubble Phase CLICK on the Document
  
multiply-post.php
+
{{JSFiddleExample
<code>
+
|title=Using Capture Phase to Enable or Disable a Toolbar
<pre>
+
|fiddle_id=r32Dz
&lt;? echo $_POST["x"]*$_POST["y"]?>
+
|desc=We bind an event in the capture phase to the div with ID ''toolbar''.  When ''e.stopPropagation()'' is called, the event does not reach the buttons in the toolbar.
</pre>
+
}}
</code>
 
  
multiply-ajax.php
+
Graphically, here is the order in which an event occurs in three generic nested elements:
<code>
 
<pre>
 
&lt;html>
 
&lt;body>
 
&lt;script>
 
function multiply()
 
{
 
  var xmlHttp;
 
  xmlHttp=new XMLHttpRequest();
 
  var x,y;
 
  x=document.getElementById("input_x").value;
 
  y=document.getElementById("input_y").value;
 
  var req="x="+x+"&y="+y;
 
  
  xmlHttp.open("POST","multiply.php",true);
+
[[File:EventPhase.gif]]
  
  xmlHttp.onreadystatechange=function()
+
Why is this useful?  Suppose you have a control panel (toolbar, etc) that you want to temporarily deactivate.  (For example, Bold/Italic/Underline buttons on a graphic text editor that currently has no content.) You could keep bubble phase event listeners on your buttons, but prevent those events from occurring by stopping the event in the capture phase on the parent element before the event reaches your buttons!  Example:
  {
 
    if(xmlHttp.readyState==4)
 
    {
 
      var pElement=document.getElementById("msg");
 
      pElement.innerHTML=xmlHttp.responseText;
 
    }
 
  }
 
  
  xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+
<source lang="javascript">
  xmlHttp.setRequestHeader("Content-length", req.length);
+
const disableToolbarFunc = function(e){
  xmlHttp.setRequestHeader("Connection", "close");
+
e.stopPropogation();
  xmlHttp.send(req);
 
 
}
 
}
&lt;/script>
 
x:&lt;input id="input_x" type="text"/ >&lt;br>
 
y:&lt;input id="input_y" type="text"/>&nbsp;&nbsp;
 
&lt;a href="javascript:multiply();">Multiply&lt;/a>
 
&lt;br>
 
------------------------&lt;/br>
 
Result:
 
&lt;p id="msg">&lt;/p>
 
&lt;/body>
 
&lt;/html>
 
</pre>
 
</code>
 
  
=Moving a target with Jquery=
+
// To disable toolbar:
<code>
+
document.getElementById("box").addEventListener("click", disableToolbarFunc, true);
<pre>
+
 
&lt;html>                                                                
+
// To re-enable toolbar:
  &lt;head>                                                                 
+
document.getElementById("box").removeEventListener("click", disableToolbarFunc, true);
  &lt;script type="text/javascript" src="http://code.jquery.com/jquery-latest.js">&lt;/script>         
+
</source>
  &lt;script type="text/javascript">                                        
+
 
  // these are for storing target locations
+
'''Word of caution:''' Like many great things in web development, capture phase does not work in versions of Internet Explorer prior to version 9.  There is no elegant substitution for older versions of Internet Explorer.
var targetLeft=0;
+
 
var targetTop=0;
+
'''Note:''' When the event reaches the innermost element, there is no distinction between capture phase and bubble phase.  The order in which event handlers were added to the element determines the order in which those callbacks are evaluated.
function moveTarget(){
+
 
    targetLeft+=10; //increase target location
+
== Document Object Model ==
    targetTop+=10;
+
 
    $("#target").css("top",targetTop); //move target to (top,left)
+
The '''Document Object Model (DOM)'''  is what enables JavaScript to manipulate the content of your web page.
    $("#target").css("left",targetLeft);
+
 
    if(targetLeft&lt;200) { //stop if we reached left=200
+
=== Nodes and Traversing the DOM ===
      window.setTimeout("moveTarget()",200); //set the next timer
+
 
    }
+
Each element on your page, whether it is a <nowiki><p>, <img/></nowiki>, a string of text, or even an attribute, is called a '''node'''.
 +
 
 +
Every node, except for the document itself, has exactly one parent.  A single node may have multiple children.
 +
 
 +
Consider the following HTML code:
 +
 
 +
<source lang="html4strict">
 +
<ul id="my-list">
 +
<li class="fruits">Apples</li>
 +
<li class="citrus">Oranges and <strong>Lemons</strong></li>
 +
<li class="berries">Cherries</li>
 +
</ul>
 +
</source>
 +
 
 +
Here, the ul with ID "my-list" has three child '''element nodes''' (the three li's) as well as four child '''text nodes''' (the whitespace counts as a text node) and a child '''attribute node'''. The second LI has one child '''text node''' as well as one child '''element node''' and one child '''attribute node'''.
 +
 
 +
The DOM can be traversed in JavaScript. First, let's look at an example.
 +
 
 +
<source lang="javascript">
 +
e = document.getElementById("my-list").getElementsByClassName("citrus")[0].lastChild.nodeName;
 +
alert(e);
 +
</source>
 +
 
 +
{{JSFiddleExample
 +
|title=Currently Selected Radio Button
 +
|fiddle_id=SHcng
 +
|desc=In pure JavaScript, in order to determine the currently selected radio button, it is necessary to iterate over an array of pointers to all possible radio buttons, and stop when you find one that is "checked".
 +
}}
 +
 
 +
The above snippet gets the element with class name '''citrus''' that is a child of the element with ID '''my-list''' (the second LI in the example above), and alerts the type of its second child node (which in this case is '''STRONG''').
 +
 
 +
Some common methods for traversing the DOM include:
 +
 
 +
* Node.parentNode
 +
* Node.childNodes - returns an array of nodes
 +
* Node.firstChild - same as Node.childNodes[0]
 +
* Node.lastChild - same as Node.childNodes[Node.childNodes.length-1]
 +
* Node.previousSibling
 +
* Node.nextSibling
 +
 
 +
You can also search for child (including all descendants) using one of the following methods:
 +
 
 +
* Node.getElementsByTagName("tag-name") - returns an array of element nodes having the tag name '''tag-name''' that are descendants of Node
 +
* Node.getElementById("id") - returns a single node having the ID '''id''' that is a descendant of Node
 +
* Node.getElementsByName("what-name") - returns an array of element nodes having their '''name''' attribute set to '''what-name'''.  Useful for radio buttons and other form elements.
 +
* Node.getElementsByClassName("class") - returns an array of nodes having the class '''class'''
 +
*: '''Note:''' As of October 2012, 82% of the browser market supports Node.getElementsByClassName ([http://caniuse.com/getelementsbyclassname more info]).  In order to support the other 18%, you need to either add your own getElementsByClassName to Node's prototype or use a JavaScript library like jQuery or MooTools.
 +
 
 +
It is common in JavaScript to have long statements like the one in the example above, where you call methods on several objects in sequence.
 +
 
 +
=== Creating, Moving, and Removing Nodes ===
 +
 
 +
You will frequently find yourself wanting to modify the DOM.  JavaScript provides methods that help you do this.
 +
 
 +
Consider the same HTML as above. If you wanted to add another element to the list, you could use this code:
 +
 
 +
<source lang="javascript">
 +
const newLi = document.createElement("li"); // creates a node with the tag name li
 +
newLi.appendChild(document.createTextNode("Broccoli"));
 +
newLi.setAttribute("class", "veggies");
 +
document.getElementById("my-list").appendChild(newLi);
 +
</source>
 +
 
 +
If you wanted to remove the apples from the list, you could do:
 +
 
 +
<source lang="javascript">
 +
const apple = document.getElementById("my-list").getElementsByClassName("fruits")[0];
 +
document.getElementById("my-list").removeChild(apple);
 +
</source>
 +
 
 +
If you wanted to move the apples to the end of the list, you could do this:
 +
 
 +
<source lang="javascript">
 +
const apple = document.getElementById("my-list").getElementsByClassName("fruits")[0];
 +
document.getElementById("my-list").appendChild(apple);
 +
</source>
 +
 
 +
Notice that '''Node.append()''' both removes a node from its previous location ''and'' appends it to its new location, which is always going to be as the last child of the parent node.
 +
 
 +
In summary, here are the methods to know from this section:
 +
 
 +
* Node.append(otherNode) - removes otherNode from its current location in the DOM (if applicable) and then adds it as the last child of Node
 +
* Node.removeChild(otherNode) - removes otherNode, a child of Node, from the DOM
 +
* document.createElement("tag-name") - create a new node with the tag name "tag-name"
 +
* document.createTextNode("text") - create a node containing only the string '''text'''
 +
* Node.setAttribute("attribute", "value") - sets the attribute node of name "attribute" to "value"
 +
 
 +
=== DOM Shortcuts ===
 +
 
 +
In the above sections, we have been creating, reading, modifying, and deleting Nodes.  This is the most "correct" way to change the content of a web page from inside JavaScript.
 +
 
 +
This section documents a few shortcuts that are not as "pure" as using Nodes but can be less confusing and cumbersome.
 +
 
 +
{{JSFiddleExample
 +
|title=Displaying Information
 +
|fiddle_id=Q3BPZ
 +
|desc=This example shows how to use some of the shortcut methods for using JavaScript to display information on the page.
 +
}}
 +
 
 +
==== textContent ====
 +
 
 +
Using textContent to display information is probably the easiest method out there.  For example, the following code overwrites whatever is in the element with ID "holder" with the string "Hello World":
 +
 
 +
<source lang="javascript">
 +
document.getElementById("holder").textContent = "Hello World";
 +
</source>
 +
 
 +
If you wanted to instead append the text, simply use '''+=''' instead of '''=''':
 +
 
 +
<source lang="javascript">
 +
document.getElementById("holder").textContent += " -  Later, he said Hello World  - ";
 +
</source>
 +
 
 +
Note that textContent displays strings literally; that is, it does not allow for HTML.  Setting the textContent property also removes any HTML that may have already been in that element.
 +
 
 +
==== innerHTML ====
 +
 
 +
If you need to use HTML in your output but don't want to use the method described earlier in this section, a straightforward strategy is to use the innerHTML property of an element. For example, the following code would add a paragraph saying "Hello World" to the element with ID "holder":
 +
 
 +
<source lang="javascript">
 +
document.getElementById("holder").innerHTML += "<p>Hello World</p>";
 +
</source>
 +
 
 +
'''Important:''' You need to be careful to prevent XSS-type attacks if you display information using innerHTML.  For example, be sure to escape a user-supplied string before appending it to innerHTML.
 +
 
 +
=== JavaScript Inspectors ===
  
  }
+
{{DoctypeTV
  $(document).ready(function() { //at the beginning create a clock timeout
+
|youtube_id=PKzrmbN-pMg
  window.setTimeout("moveTarget()",200); //call this function in 200 ms.
+
|time=4m13s
     
+
|desc=Using Firebug, WebKit Inspector, and IE Developer Tools
});
+
}}
  
  &lt;/script>                                                             
+
Various browsers and browser plugins give you, the developer, tools to debug your code, inspect the DOM, and much more. Using these tools is essential for an efficient workflow.
&lt;/head>                                                               
 
&lt;body>                                                                 
 
  &lt;!-- this is my target-->                                       
 
&lt;img id="target"  src="http://upload.wikimedia.org/wikipedia/commons/thumb/8/85/Smiley.svg/180px-Smiley.svg.png" style="position:relative"/>
 
  
   
+
* '''Firebug'''. Firebug is a plugin for Firefox that is a toolkit full of web developer tools, one of which is a DOM inspector.  To inspect the DOM of a web page, simply open the Firebug window while viewing the web page.
  &lt;/body>                                                               
+
* '''WebKit Inspector'''.  The WebKit Inspector, which is available in both Chrome and Safari, enables you to see the DOM tree and relationships between elements. However, its DOM inspection tools are not as robust as those of Firebug.
  &lt;/html>
+
* '''Opera Dragonfly'''.  The web browser Opera comes with a web developer toolkit similar to the WebKit Inspector called Dragonfly.  It is important that you test your sites in Opera, because although Opera has only a small fraction of the desktop browser market, it is second only to WebKit on the mobile market. Opera also has extremely strong CSS support, so it is good for testing for bugs in your CSS.
  
 +
All of the above-mentioned tools enable you to look at the DOM of your web page and find what properties and methods are associated with each node.  This is helpful because if you have JavaScript that manipulates HTML elements, you cannot tell which properties are associated with which elements by looking at the source code alone.
  
</pre>
+
[[Category:Module 6]]
</code>
 

Latest revision as of 16:00, 2 March 2020

JavaScript is the most widely used scripting language for implementing client-side functionality in Web applications, and, in recent years, it's become very popular for server-side application, too. Unlike PHP, JavaScript code can be interpreted and executed in a client's web browser, instead of on the web server, depending on how it's being used.

JavaScript? Did you mean Java?

JavaScript is a prototype-based programming language focused on web interactivity. It was first introduced in Netscape Navigator, and it in turn gave rise to what is now ECMAScript. Originally, JavaScript was called "LiveScript". Sun, the developer of Java at the time, wanted a language that would complement its compiled Java language, and so LiveScript was renamed JavaScript.

Beyond that, Java and JavaScript are as similar as Ham and Hamster.

Java and JavaScript have similar syntax, but the under workings are quite different. For example, Java requires strict typing, but JavaScript allows for dynamic typing. Java is object-oriented, but JavaScript is prototype-oriented. Java is compiled, but JavaScript is interpreted. Java supports event listeners, but JavaScript makes them a fundamental part of the language. Java variables are scoped to the innermost method or loop, but JavaScript variables are scoped only to the innermost function.

JavaScript Language Components

This section highlights some features of the JavaScript language that differentiate it from other languages. For a more comprehensive JavaScript tutorial, the following tutorials are both quality:

  • Mozilla Developer Network: Great for learning JavaScript for the first time. Advocates best practices for modern JavaScript development.
  • QuirksMode: More advanced than the Mozilla tutorial, but it thoroughly covers the most powerful aspects of pure JavaScript and gives unparalleled advice on browser compatibility.

Advice: Do NOT Google for "JavaScript Tutorial". The first few hits advocate bad or outdated practices. Stick with the ones listed here.

Variables and Scope

To define a variable in JavaScript, use the let keyword.

let foo = "bar";

To define a constant in JavaScript, use the const keyword.

const foo = "bar";

Note: We should NOT see any variables initialized with var in your code. Some might appear in the linked examples, since those are from older versions of the language so please replace those with let and const in your mind Var creates ambiguity to anyone reading your code and is becoming deprecated in JavaScript.

All variables are objects. In the case above, the variable foo is an object of the class String.

Notice that like PHP, you do not have to explicitly define a type for a variable like int or String; this is because JavaScript and PHP are dynamically typed languages.

JavaScript code can access any variable higher in the “function tree”, but not vice-versa. This is called scope. All functions create their own scope.

When you reference a variable, JavaScript will look up through the "function tree" until it finds the variable you asked for. This means that you could define variables of the same name as global variables inside of functions. For demonstration of concept:

const a = "hello";
const b = "world";

function sayGoodByeWorld(){
	const a = "goodbye";

	alert(a); // goodbye
	alert(b); // world
}

sayGoodByeWorld();

alert(a); // hello

Object Literals

A very common way of storing and transporting data in JavaScript is by using objects. You can define an object with certain properties using an object literal:

const apple = {
	color: "red",
	flavor: "sweet",
	season: "autumn"
}

alert(apple.color);  // red

Functions

To define a function in JavaScript, use the function keyword.

function sayHello(){
	alert("Hello World");
}

sayHello(); // call the function

Pass an argument to a function like this:

function sayHello(name){
	alert("Hello, "+name);
}

sayHello("Todd"); // call the function and pass an argument

Arrow Functions

The latest versions of JavaScript have introduced arrow functions. They provide a cleaner syntax for writing functions, and maintain scope when using classes.

The general syntax is:

(param1, param2, ... , paramN) => { statements }

//removing the brackets around { statements } is equivalent to
{ return statements; }

//No parameters should be 2 empty parentheses as such: 
() => { statements }

The example above could be written as follows:

const sayHello = (name) => alert("Hello, "+name);
sayHello("Todd");

Arrow functions can be particularly useful when you're looking to contain function logic within cleanly and compactly. For example, iterating over an array and making updates to each item of the array.

let arr = [1,2,3,4,5];
let newArr = arr.map(number => number*5); //newArr is an array containing [5,10,15,20,25]

Functions are Objects

In JavaScript, functions are objects. This means that they can be assigned to variables, manipulated on the fly, and even passed as arguments to other functions! This is an extremely important feature of JavaScript that makes it such a robust language for web development.

You create a function variable like this:

const sayHello = function(){
	alert("Hello World");
}

sayHello(); // call the function

Observe that you can make scope-dependent functions in this way.

Closures

Watch on DOCTYPE

JavaScript Closures

A closure is a way to separate a certain snippet of JavaScript code from the global scope. This is useful if you do not want to "muck up" global variables. Closures are nothing more than anonymous functions that are called as soon as they are created:

const a = "hello";

(​​​​function(){
	const b = "world";
	
	alert(a); // hello
	alert(b); // world
})();

alert(a); // hello
alert(b); // ReferenceError: b is not defined​​​​​​​​​​​​​​​

Example: Passing Variables to a Closure

View in JSFiddle

This example demonstrates how you can "save" previous versions of a variable using closures. This is possible because of scoping and the fact that function variables can be returned as objects.

Most JavaScript libraries (like jQuery) write all of their code in a closure. What this means is that except for one or two variable names (jQuery or $), everything associated with the library is completely self-contained.

Prototypal Inheritance

JavaScript implements prototypal inheritance, as opposed to a language like Java or C++, which implements classical inheritance. JavaScript is one of only a handful of languages implementing prototype-based inheritance.

Here's how it works. Every callable object (function) has a prototype. When instances of that object are created, their properties and methods are copied (inherited) from the prototype. Additionally, changes made to the prototype later in the program are "copied" to every instance.

For example, if you wanted to make a method on all strings that added a “!”, you could modify String’s prototype:

String.prototype.bang = function(){
	return this+"!"; // Notice: the context is the instance itself
}

alert("Hello".bang()); // alerts Hello!

To "extend" an object, just copy its prototype to a new object. However, since classical inheritance and prototypal inheritance are different concepts, copying prototypes may have results that you don't expect. This article seems to have a pretty good explanation of how to "inherit" prototypes with example implementations.

Extending Built-In Prototypes

You should be aware that there is an active debate in the web development community about whether it is good programming style to extend the prototypes of built-in objects like String and Array, such as in the String.prototype.bang example above. There are legitimate arguments on both sides. This Stack Overflow post has good links to some articles discussing this issue.

Context

Watch on DOCTYPE

The this Variable in JavaScript

Every function is called on a certain object, which is not necessarily the same object in which it was defined. This is called context.

To call a function on an arbitrary context, use either call or apply. call takes a list of arguments, while apply takes them all in an array.

To access the current context, use the this keyword. Demonstration of concept:

const sayThisColor = function(){
	alert(this.color);
}

const apple = { color: "red" }

sayThisColor();   // undefined
sayThisColor.call(apple); // red

Events

Events are really what make JavaScript such a powerful language for web development.

Rather than being thread based, JavaScript is event based. Since all JavaScript code runs in a single thread, there are no concurrency issues. When an event occurs, JavaScript automatically calls the event callback as soon as all previous events' callbacks have finished executing.

Code in the form of a callback function is associated with events via a listener. For example, the following JavaScript causes sayHello() (the callback function) to be run whenever the button with ID "hello" is clicked (the event):

const sayHello = function(){
	alert("Hello World");
}

document.getElementById("hello").addEventListener("click", sayHello, false);

Example: Binding Callbacks to a Button Click

View in JSFiddle

In this example, notice how we bind the callback function when the DOMContentLoaded event fires. This is because JavaScript requires that the button has been parsed by the browser before it can add event listeners to it.

The addEventListener method takes three parameters:

  • The event type
  • The callback function
    The callback function is passed one parameter: the event object.
  • A boolean representing bubble (false) or capture (true) phase
    You usually want Bubble phase. For more information on event phase, see #Event Phase

Note that versions of Internet Explorer prior to version 9 required that you use a different, albeit similar, function for assigning event listeners called attachEvent. attachEvent takes the same arguments as addEventListener, except you need to put on before the event type (e.g. "onclick"), and the third argument (phase) is not necessary.

It is perfectly valid to use an anonymous function as your callback function:

document.getElementById("hello").addEventListener("click", function(event){
	alert(`Hello, World!  Event Type: ${event.type}`);
}, false);

QuirksMode has perhaps the best series of articles about the ins and outs of JavaScript events on the internet: http://www.quirksmode.org/js/contents.html#events

The Event Object

Callback functions are passed one argument: an event object. You see above that one property of the event object is event.type. To see the full list of properties of the event object, you could run the code:

document.getElementById("my_btn").addEventListener("click", function(event){
	let strout = "";
	for(var i in event){
		strout += `${i}: ${event[i]}\n`;
	}
	console.log(strout);
}, false);

Some of the most useful properties and methods include:

  • event.target references the object on which the event occurred.
  • event.currentTarget references the object whose listener is currently being processed.
    Note: event.target and event.currentTarget might be the same or might be different, depending on whether you are listening for bubbled events.
  • event.preventDefault() stops the normal result of the event from being executed. For example, if you listen for a form's submit event, you can call event.preventDefault() to stop the form from being submitted.
  • event.stopPropagation() prevents any other event listeners from being executed. For more detail, read the section on Event Phase below.

For more detail on the event object, see the W3C specification.

Note: If your callback function does not take any parameters, it will still run; you just won't have as easy of access to the event object.

Event Handlers and Memory Management

JavaScript is an automatically garbage-collected language, meaning that memory management is mostly taken care of for you. However, there are some instances when you need to be careful about creating "zombie" objects. In JavaScript, this mostly revolves around the idea of event listeners.

I could give an explanatory example, but instead I'll tell you straightaway that the moral of the story is that for every "addEventListener", there should probably be a "removeEventListener". Here are some good articles to satisfy your hunger for more details on event listeners and JavaScript memory management:

When you start working with Node.JS in the next module, it's more important than ever to keep good accounting of your event listeners.

Event Phase

In JavaScript, events occur in two phases: Capture Phase and Bubble Phase. Consider the following HTML document:

<!DOCTYPE html>
<html>
<head><title>Event Test</title></head>
<body>
  <div id="box">
    <button id="btn">
      Hello
    </button>
  </div>
</body>
</html>

Suppose the user clicks on the "Hello" button. Events will be fired in the following order:

  1. Capture Phase CLICK on the Document
  2. Capture Phase CLICK on the Body
  3. Capture Phase CLICK on the Div#box
  4. Target Phase CLICK on the Button#btn
  5. Bubble Phase CLICK on the Div#box
  6. Bubble Phase CLICK on the Body
  7. Bubble Phase CLICK on the Document

Example: Using Capture Phase to Enable or Disable a Toolbar

View in JSFiddle

We bind an event in the capture phase to the div with ID toolbar. When e.stopPropagation() is called, the event does not reach the buttons in the toolbar.

Graphically, here is the order in which an event occurs in three generic nested elements:

EventPhase.gif

Why is this useful? Suppose you have a control panel (toolbar, etc) that you want to temporarily deactivate. (For example, Bold/Italic/Underline buttons on a graphic text editor that currently has no content.) You could keep bubble phase event listeners on your buttons, but prevent those events from occurring by stopping the event in the capture phase on the parent element before the event reaches your buttons! Example:

const disableToolbarFunc = function(e){
	e.stopPropogation();
}

// To disable toolbar:
document.getElementById("box").addEventListener("click", disableToolbarFunc, true);

// To re-enable toolbar:
document.getElementById("box").removeEventListener("click", disableToolbarFunc, true);

Word of caution: Like many great things in web development, capture phase does not work in versions of Internet Explorer prior to version 9. There is no elegant substitution for older versions of Internet Explorer.

Note: When the event reaches the innermost element, there is no distinction between capture phase and bubble phase. The order in which event handlers were added to the element determines the order in which those callbacks are evaluated.

Document Object Model

The Document Object Model (DOM) is what enables JavaScript to manipulate the content of your web page.

Nodes and Traversing the DOM

Each element on your page, whether it is a <p>, <img/>, a string of text, or even an attribute, is called a node.

Every node, except for the document itself, has exactly one parent. A single node may have multiple children.

Consider the following HTML code:

<ul id="my-list">
	<li class="fruits">Apples</li>
	<li class="citrus">Oranges and <strong>Lemons</strong></li>
	<li class="berries">Cherries</li>
</ul>

Here, the ul with ID "my-list" has three child element nodes (the three li's) as well as four child text nodes (the whitespace counts as a text node) and a child attribute node. The second LI has one child text node as well as one child element node and one child attribute node.

The DOM can be traversed in JavaScript. First, let's look at an example.

e = document.getElementById("my-list").getElementsByClassName("citrus")[0].lastChild.nodeName;
alert(e);

Example: Currently Selected Radio Button

View in JSFiddle

In pure JavaScript, in order to determine the currently selected radio button, it is necessary to iterate over an array of pointers to all possible radio buttons, and stop when you find one that is "checked".

The above snippet gets the element with class name citrus that is a child of the element with ID my-list (the second LI in the example above), and alerts the type of its second child node (which in this case is STRONG).

Some common methods for traversing the DOM include:

  • Node.parentNode
  • Node.childNodes - returns an array of nodes
  • Node.firstChild - same as Node.childNodes[0]
  • Node.lastChild - same as Node.childNodes[Node.childNodes.length-1]
  • Node.previousSibling
  • Node.nextSibling

You can also search for child (including all descendants) using one of the following methods:

  • Node.getElementsByTagName("tag-name") - returns an array of element nodes having the tag name tag-name that are descendants of Node
  • Node.getElementById("id") - returns a single node having the ID id that is a descendant of Node
  • Node.getElementsByName("what-name") - returns an array of element nodes having their name attribute set to what-name. Useful for radio buttons and other form elements.
  • Node.getElementsByClassName("class") - returns an array of nodes having the class class
    Note: As of October 2012, 82% of the browser market supports Node.getElementsByClassName (more info). In order to support the other 18%, you need to either add your own getElementsByClassName to Node's prototype or use a JavaScript library like jQuery or MooTools.

It is common in JavaScript to have long statements like the one in the example above, where you call methods on several objects in sequence.

Creating, Moving, and Removing Nodes

You will frequently find yourself wanting to modify the DOM. JavaScript provides methods that help you do this.

Consider the same HTML as above. If you wanted to add another element to the list, you could use this code:

const newLi = document.createElement("li");  // creates a node with the tag name li
newLi.appendChild(document.createTextNode("Broccoli"));
newLi.setAttribute("class", "veggies");
document.getElementById("my-list").appendChild(newLi);

If you wanted to remove the apples from the list, you could do:

const apple = document.getElementById("my-list").getElementsByClassName("fruits")[0];
document.getElementById("my-list").removeChild(apple);

If you wanted to move the apples to the end of the list, you could do this:

const apple = document.getElementById("my-list").getElementsByClassName("fruits")[0];
document.getElementById("my-list").appendChild(apple);

Notice that Node.append() both removes a node from its previous location and appends it to its new location, which is always going to be as the last child of the parent node.

In summary, here are the methods to know from this section:

  • Node.append(otherNode) - removes otherNode from its current location in the DOM (if applicable) and then adds it as the last child of Node
  • Node.removeChild(otherNode) - removes otherNode, a child of Node, from the DOM
  • document.createElement("tag-name") - create a new node with the tag name "tag-name"
  • document.createTextNode("text") - create a node containing only the string text
  • Node.setAttribute("attribute", "value") - sets the attribute node of name "attribute" to "value"

DOM Shortcuts

In the above sections, we have been creating, reading, modifying, and deleting Nodes. This is the most "correct" way to change the content of a web page from inside JavaScript.

This section documents a few shortcuts that are not as "pure" as using Nodes but can be less confusing and cumbersome.

Example: Displaying Information

View in JSFiddle

This example shows how to use some of the shortcut methods for using JavaScript to display information on the page.

textContent

Using textContent to display information is probably the easiest method out there. For example, the following code overwrites whatever is in the element with ID "holder" with the string "Hello World":

document.getElementById("holder").textContent = "Hello World";

If you wanted to instead append the text, simply use += instead of =:

document.getElementById("holder").textContent += " -  Later, he said Hello World  - ";

Note that textContent displays strings literally; that is, it does not allow for HTML. Setting the textContent property also removes any HTML that may have already been in that element.

innerHTML

If you need to use HTML in your output but don't want to use the method described earlier in this section, a straightforward strategy is to use the innerHTML property of an element. For example, the following code would add a paragraph saying "Hello World" to the element with ID "holder":

document.getElementById("holder").innerHTML += "<p>Hello World</p>";

Important: You need to be careful to prevent XSS-type attacks if you display information using innerHTML. For example, be sure to escape a user-supplied string before appending it to innerHTML.

JavaScript Inspectors

Watch on DOCTYPE

Using Firebug, WebKit Inspector, and IE Developer Tools

Various browsers and browser plugins give you, the developer, tools to debug your code, inspect the DOM, and much more. Using these tools is essential for an efficient workflow.

  • Firebug. Firebug is a plugin for Firefox that is a toolkit full of web developer tools, one of which is a DOM inspector. To inspect the DOM of a web page, simply open the Firebug window while viewing the web page.
  • WebKit Inspector. The WebKit Inspector, which is available in both Chrome and Safari, enables you to see the DOM tree and relationships between elements. However, its DOM inspection tools are not as robust as those of Firebug.
  • Opera Dragonfly. The web browser Opera comes with a web developer toolkit similar to the WebKit Inspector called Dragonfly. It is important that you test your sites in Opera, because although Opera has only a small fraction of the desktop browser market, it is second only to WebKit on the mobile market. Opera also has extremely strong CSS support, so it is good for testing for bugs in your CSS.

All of the above-mentioned tools enable you to look at the DOM of your web page and find what properties and methods are associated with each node. This is helpful because if you have JavaScript that manipulates HTML elements, you cannot tell which properties are associated with which elements by looking at the source code alone.