JavaScript is universally deployed in all of the web browsers. Earlier, we discussed elements of JavaScript programming like basics, Arrays, Strings, Objects, Functions etc. With this page and beyond, we discuss the application of JavaScript to web browsers and its key role in addressing content and behavior of web pages.
This introduction covers two of the key browser-based JavaScript objects: window and document. The document object is, in fact, a derived object from the window object itself.
In a browser, the default scope for all variables and functions is the scope of a global object: the window object. The window object provides a distinct and fairly independent programming context. Thus, if we define a variable (let us say var1) or a function (func1), then they reside as properties of this object and can be accessed from within that window (as window.var1 or window.func1).
A browser can have multiple windows (tabs, windows, frames) and JavaScript provides each of these elements with their own programming environment and they each get their own global window object. Thus, variables and functions defined in one window (frames or tabs) would not be automatically visible to other windows (frames, or tabs) even in the same browser. This limitation on scope provides a useful isolation against security and collisions in having same names for variables and functions.
When we load a page in the browser, the browser loads the page content within the context of the window object; as we will see shortly that it is the document property of the window object that handles the content that is rendered on an HTML page. Thus, when we load a page, the content gets displayed on the page and the loading stage is considered complete. Beyond that point, JavaScript provides event handlers which make the behavior of the page more dynamic. More on events a little later!
Let us begin by exploring this global window object using a simple example (provided below). The example uses a simple for/in loop to iterate through all the properties of the window object; note that a for/in loop only lists those properties that are enumerable.
<!doctype html> <html> <div id="div_id"> </div> <script type="text/javascript"> // Get a handle for the div element. var elem = document.getElementById('div_id'); // Define two dummy variables. var dummyVariable1 = 1, dummyVariable2 = 2; // Print properties of the window object. for (var item in window) { elem.innerHTML += item + ", "; } </script> </html>
Here is the output with Firefox 10.
window, document, InstallTrigger, elem, dummyVariable1, dummyVariable2, item, addEventListener, removeEventListener, dispatchEvent, dump, name, parent, top, self, sessionStorage, localStorage, globalStorage, onmouseenter, onmouseleave, getSelection, scrollByLines, getComputedStyle, location, history, locationbar, menubar, personalbar, scrollbars, statusbar, toolbar, status, close, stop, focus, blur, length, opener, frameElement, navigator, applicationCache, alert, confirm, prompt, print, showModalDialog, postMessage, atob, btoa, matchMedia, screen, innerWidth, innerHeight, scrollX, pageXOffset, scrollY, pageYOffset, scroll, scrollTo, scrollBy, screenX, screenY, outerWidth, outerHeight, scrollByPages, sizeToContent, content, closed, crypto, pkcs11, controllers, defaultStatus, mozInnerScreenX, mozInnerScreenY, scrollMaxX, scrollMaxY, fullScreen, back, forward, home, moveTo, moveBy, resizeTo, resizeBy, updateCommands, find, mozPaintCount, mozRequestAnimationFrame, mozAnimationStartTime, URL, onafterprint, onbeforeprint, onbeforeunload, onhashchange, onmessage, onoffline, ononline, onpopstate, onpagehide, onpageshow, onresize, onunload, ondevicemotion, ondeviceorientation, setTimeout, setInterval, clearTimeout, clearInterval, setResizable, captureEvents, releaseEvents, routeEvent, enableExternalCapture, disableExternalCapture, open, openDialog, frames, onabort, onblur, oncanplay, oncanplaythrough, onchange, onclick, oncontextmenu, ondblclick, ondrag, ondragend, ondragenter, ondragleave, ondragover, ondragstart, ondrop, ondurationchange, onemptied, onended, onerror, onfocus, oninput, oninvalid, onkeydown, onkeypress, onkeyup, onload, onloadeddata, onloadedmetadata, onloadstart, onmousedown, onmousemove, onmouseout, onmouseover, onmouseup, onmozfullscreenchange, onmozfullscreenerror, onpause, onplay, onplaying, onprogress, onratechange, onreset, onscroll, onseeked, onseeking, onselect, onshow, onstalled, onsubmit, onsuspend, ontimeupdate, onvolumechange, onwaiting, oncopy, oncut, onpaste, onbeforescriptexecute, onafterscriptexecute, mozIndexedDB, performance,
Since everything is part of global object, when we print window object, we also see variables "dummyVariablel" and "dummyVariable2" being printed as part of it. If we were to define a function in the above example, then the above output would show that the name of that function that as well.
The above output shows that JavaScript provides a large number of properties for the window object. We can use these properties to modify the behavior of the window object to suit the website behavior for the end-user. In this chapter and in couple of chapters beyond, we will focus on various properties provided by the window object.
The above list also contains several methods that allow us to interact with users like alert(), confirm(), prompt(). Method alert() pops up a window to display text to the user along with an OK button. Please note that this window is not considered a pop-up window and even if we turn off pop-up windows in a browser, alert() messages would still be visible. Unlike alert(), a confirm() box shows some text to the user along with OK and Cancel buttons; this method expects the user to either confirm it (by clicking the OK button) or dismiss it (by clicking the Cancel button). The third method, prompt() serves a different purpose: this method opens a pop-window with an input text element to accept input from the user.
We should note that using a lot of alert, confirm, or prompt boxes makes the user-interaction less smooth and hence, these should be used sparingly.
Next, the output also shows a lot of properties starting with "on" e.g. onclick. These properties represent specific events (e.g. submitting an HTML Form) and if needed, one can add callbacks to each of these events. And, when an event occurs, then JavaScript invokes the associated callback! For example, the event "onclick" happens when the user single clicks the mouse. We will revisit events later.
The window object also contains various built-in objects like Array, Boolean, Number, String, Date etc. These do not show in the list above since we use a simple for/in loop to iterate over all the properties of the window -- a for/in loops lists all properties of an object (own or inherited) as long as they are enumerable. However, built-in objects like Array, Boolean, Date, and Math are non-enumerable (they are owned by the window object) and hence do not show up in the above list. If we were to use call Object.getOwnPropertyNames() for the window object, (e.g. "var prop = Object.getOwnPropertyNames(obj);"), then prop would be an array containing the above built-in objects like Array, Boolean, Number, and String. One key trade-off here would be that getOwnPropertyNames() prints only those properties (enumerable or non-enumerable) that are owned by an object and not those that are inherited by an object. So, we might find that getOwnPropertyNames() will miss some of the properties that are listed in the above output provided by the for/in loop.
With multiple windows, if we were to extend a built-in objects in one of the windows, then it would not be available automatically in other windows! We will revisit the case of multiple windows and iframes and show how we can access properties of one from another.
Lastly, the window object also has its own prototype (parent). To get the prototype of window, we can use "var parentOfWindow = Object.getPrototypeOf(window)". Now, the ultimate prototype for all objects is the Object.prototype. If we were to recursively track prototypes of window (starting with immediate prototype and then looking at the prototype of the immediate prototype, and so on), then we would find that the last prototype would be Object.prototype.
The earlier output shows that window object contains many useful properties. One of the key properties of the window object is the document object. Among other things, the document object houses all the methods that handle the content that gets displayed on an HTML page.
Like the earlier example of window object, let us go through an example to explore properties of the document object. Once again, we use a for/in loop to iterate over all the (enumerable) properties of the document object.
<!doctype html> <html> <div id="div_id"> </div> <script type="text/javascript"> // Get a handle for the div element. var elem = document.getElementById('div_id'); // Print properties of the document object for (item in window.document) { elem.innerHTML += item + ", "; } </script> </html>
When we run the above program, JavaScript prints all the methods (fairly large, if we must say!) supported by window.document. We print the output with Firefox 10. In addition to several basic properties, the document object also contains properties that enable an HTML document to handle various types of events.
location, querySelector, querySelectorAll, evaluate, createExpression, createNSResolver, addEventListener, removeEventListener, dispatchEvent, body, anchors, links, URL, forms, cookie, images, domain, designMode, getElementsByName, write, writeln, getSelection, documentElement, implementation, doctype, documentURI, defaultView, title, referrer, activeElement, onreadystatechange, onmouseenter, onmouseleave, getElementsByTagName, getElementsByTagNameNS, getElementById, createDocumentFragment, createElement, createElementNS, importNode, createTextNode, adoptNode, createNodeIterator, createEvent, getElementsByClassName, hasFocus, elementFromPoint, nodeName, nodeValue, nodeType, parentNode, parentElement, childNodes, firstChild, lastChild, previousSibling, nextSibling, attributes, ownerDocument, namespaceURI, prefix, localName, baseURI, textContent, insertBefore, replaceChild, removeChild, appendChild, hasChildNodes, cloneNode, normalize, isSupported, hasAttributes, compareDocumentPosition, lookupPrefix, isDefaultNamespace, lookupNamespaceURI, isEqualNode, setUserData, getUserData, contains, createComment, createCDATASection, createProcessingInstruction, createAttribute, createAttributeNS, inputEncoding, createRange, createTreeWalker, characterSet, dir, readyState, lastModified, styleSheets, preferredStyleSheetSet, selectedStyleSheetSet, lastStyleSheetSet, styleSheetSets, enableStyleSheetsForSet, contentType, mozSyntheticDocument, currentScript, releaseCapture, mozSetImageElement, mozFullScreenElement, mozCancelFullScreen, mozFullScreen, mozFullScreenEnabled, mozHidden, mozVisibilityState, ELEMENT_NODE, ATTRIBUTE_NODE, TEXT_NODE, CDATA_SECTION_NODE, ENTITY_REFERENCE_NODE, ENTITY_NODE, PROCESSING_INSTRUCTION_NODE, COMMENT_NODE, DOCUMENT_NODE, DOCUMENT_TYPE_NODE, DOCUMENT_FRAGMENT_NODE, NOTATION_NODE, DOCUMENT_POSITION_DISCONNECTED, DOCUMENT_POSITION_PRECEDING, DOCUMENT_POSITION_FOLLOWING, DOCUMENT_POSITION_CONTAINS, DOCUMENT_POSITION_CONTAINED_BY, DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC, compatMode, head, embeds, plugins, scripts, open, close, execCommand, execCommandShowHelp, queryCommandEnabled, queryCommandIndeterm, queryCommandState, queryCommandSupported, queryCommandText, queryCommandValue, fgColor, bgColor, linkColor, vlinkColor, alinkColor, applets, clear, captureEvents, releaseEvents, routeEvent, getAnonymousNodes, getAnonymousElementByAttribute, addBinding, removeBinding, getBindingParent, loadBindingDocument, onabort, onblur, oncanplay, oncanplaythrough, onchange, onclick, oncontextmenu, ondblclick, ondrag, ondragend, ondragenter, ondragleave, ondragover, ondragstart, ondrop, ondurationchange, onemptied, onended, onerror, onfocus, oninput, oninvalid, onkeydown, onkeypress, onkeyup, onload, onloadeddata, onloadedmetadata, onloadstart, onmousedown, onmousemove, onmouseout, onmouseover, onmouseup, onmozfullscreenchange, onmozfullscreenerror, onpause, onplay, onplaying, onprogress, onratechange, onreset, onscroll, onseeked, onseeking, onselect, onshow, onstalled, onsubmit, onsuspend, ontimeupdate, onvolumechange, onwaiting, oncopy, oncut, onpaste, onbeforescriptexecute, onafterscriptexecute,
The output shows that window.document has several (enumerable) properties.
Next, we present a small example (provided below) that changes the background color of the page and uses some of the methods provided by the document object; This example uses two methods of the document object: getElementById() and getElementsByTagName(); we have already seen the getElementById() method in various examples before. The examples uses getElementsByTagName() to get a handle of the body element of the page and stores it as bodyElem variable.
The example uses setInterval() to wake up every 1 second (1000 milli-seconds) and then change the backgroundColor style of the bodyElem by selecting the next color from the arrColors array. Once we select all the colors from this array, we cancel the setInterval() and stop. Upon running, we would find that the page changes color and also updates the text every one second.
<!doctype html> <html> <div id="div_id"></div> <script type="text/javascript"> //Global Variables var counter = 0; var color = ["violet", "indigo", "blue", "green", "yellow", "orange", "red", "white"]; // Get a handle for the div element. var elem = document.getElementById("div_id"); // Get a handle for the body element. var bodyElem = document.getElementsByTagName("body")[0]; // Change the background color. function changeTheColor() { elem.innerHTML = "<br>The color is " + color[counter]; bodyElem.style.backgroundColor = color[counter]; // Stop the interval when we are done with all arrColors. if ((++counter) == color.length) { clearInterval(retVal); } } // Set a timer to change the background color. Store the return value. var retVal = setInterval(changeTheColor, 1000); </script> </html>
Often, different browsers differ in terms of their properties (methods and variables) that they provide to window and window-based objects (like document, location, history etc). For this reason, if we were to run the above examples of printing properties of window and document objects, then output would be different for different browsers. Hence, different browsers, like Chrome, Firefox (Firefox (Mozilla), Microsoft Internet Explorer, Safari, and Opera would print varying number of properties for these two objects.
This inconsistency exists because some of the browsers do not implement the complete list of available features/APIs that are recommended by the standards; web standards are provided by W3C (www.w3c.org). Or, some of the browsers go ahead and implement their own (non-standard) properties. For example, in the earlier output of printing properties of window and document objects, properties starting with moz (like mozIndexedDB) are properties specific to Firefox (Mozilla). Sometimes, these properties specific to a browser can become so popular that the web standards are provided to formalize them.
Browser incompatibilities is an unfortunate fact of web-development! Keeping track of what methods works in what browsers can make web-development a lot less fun. The good news is that these incompatibilities have motivated a lot of frameworks that take care of the underlying browser differences by providing a common set of APIs. One such popular framework is that of jQuery (www.jquery.com).