JavaScript

JavaScript - The Language of the Browser

,JavaScript - The Lanuage of the Browser

Web page by Kevin Harris of Homer IL

Please contact Kevin Harris of Homer IL concerning this web site

"Java is to JavaScript as Car is to Carpet."



The best tutorial I have found for understanding JavaScript, the programming language (under the hood) is JavaScript: Understanding the Weird Parts by Anthony Alicea. Other valuable references to JavaScript include:


What is JavaScript?

JavaScript (JS) is an scripting language implemented in all the major web browsers. JS can be described as an open-source, dynamically-typed, single-threaded, synchronous, object-oriented language with first-class functions. Unfortunately, many users of JavaScript do not appreciate its abilities as a functional language, but then there are some who do not even make use of its object-oriented capabilities. While it is heavily used on the client-side of web applications, it should be noted that JS usage on the server-side is making a resurgence. From the buggy 1994 Server-Side JavaScript (SSJS) engine by Netscape called Livewire, to the refined SSJS engines in products such as Node.js.

Note: The term "JavaScript" is currently a register trademark of Oracle America Incorporated. Technically it is the language standard called "ECMAScript" that is supported to varying degrees by the major browsers. However many people use JavaScript as a generic term when referring to the dialects of ECMAScript.


JavaScript: Written by University of Illinois Graduate Brendan Eich

Brendan Eich developed the language which became know as JavaScript when it was introduced in 1995 as part of Netscape Navigator version 2.0. It is frequently reported that Eich created the interpreter in 10 days and that the name was changed from Mocha, to LiveScript, and then to JavaScript as a marketing move because of the popularity of the Java language at the time. This has been know to cause confusion because JavaScript is a very different language than Java. Further problems arise when people see the similarities in JavaScript's syntax to other main stream languages and develop incorrect expectations about how the language works. JavaScript sounds like Java, and its syntax looks similar to Java, but it behaves quite differently.

JavaScript was designed to behavior differently than other languages which are commonly used with web applications, such as C#, Java, PHP, etc. Early users of JavaScript expected it to behave like other mainstream languages they were using. When it didn't, they were quick to claim the language was buggy. Another major reason JavaScript initially received a negative perception, by some, was actually do to the poorly written and inconsistently implemented DOM with which it interacted. To add more confusion to the situation, JavaScript clones, such as Microsoft's JScript, tended to have subtle alternate behaviors to the original. The early browsers contained a great deal of inconsistency about which JavaScript capabilities they could handle. Fortunately, in 1996 Netscape submitted JavaScript to ECMA International for consideration as an industry standard. In June 1997 the Ecma International standards organization published their ECMA-262 specification for a standardized version of the JavaScript/JScript languages they called ECMAScript. The language standard called "ECMAScript" is supported to varying degrees by the major browsers. As time progresses these implementation differences between the major browsers become increasingly smaller.


JavaScript: Unlike Other Mainstream Languages

People recognize syntax in JavaScript that resemble other mainstream languages. This frequently leads them to erroneous expectations about JavaScript's behaviors, especially when they try to parrot the language. Even some authors incorrectly, or incompletely, describe the way JavaScript works. It is not uncommon to see JavaScript's "Hoisting" incorrectly described as the parser moving, or "hoisting" the programs variables and functions to the top of the program. This incorrect notion can be quickly disproved with a few simple examples. Understanding the foundational aspects of JavaScript is key to understanding how JavaScript code behaves.


JavaScript: The Programming Language

While JavaScript may look like other languages, such as Java or C++, it is nothing like those other languages. JavaScript is a different mind set, which causes some people difficulty. Understanding the different nature of JavaScript will reveal the utility and power of the language, and explain why the language is so widely used. There are many popular JavaScript libraries which are very useful, such as:

Having a good foundational knowledge of JavaScript will allow you to look at the source JavaScript code in these libraries and understand what is happening in these higher-level abstractions.

Some of the concepts used in differentiating JavaScript from other main stream languages include:

  • Lexical Environments - where the code exists within a program and what surrounds it. For example, a variable may exist inside of a function.
  • Execution Context - a wrapper to help manage the running code. It may contain things in addition to the code written by the programmer.
  • Name/Value Pair - a name which maps to a unique value within an execution context. Name/Value pairs can be nested. (i.e. a collection of Name/Value pairs.)
  • Objects - In JavaScript, an object is a collection of Name/Value pairs. Think: JavaScript Object Notation (JSON). In other languages objects consist of other components, such as properties and methods. But in JavaScript an object is simply a collection of Name/Value pairs. Objects can be nested.
  • Variable Environment - where the variable is defined and how it relates to other variables in memory. Includes the concept of "Scope", or where can we see the variable.
  • unknown - a special value (keyword) used to indicate a variable has been allocated, but not assigned a value.

A JavaScript program typically runs in several execution contexts. It starts running in the Global (or base) Execution Context. The global execution context automatically creates:

  • Global Object
  • 'this' variable

All the major browsers have Developer Tools (F12) built in. Among all the wonderful features inside Developer Tools is a JavaScript console. Another useful tool for running JavaScript is a free editor by Adobe called backets. If you create an empty JavaScript file and run using brackets, you can open the Developer Tools Console and enter 'this' to reveal the global exection context within a browser is the Windows Object.

.Global Execution Context in Browser is the Window Object


The Global Execution Context within a Browser is the Window Object

When variables and functions are created at the global level (i.e. not inside a function) then the variables and functions are attached to the Window object. The JavaScript engine is creating the Global Execution Context, the 'this' variable (pointing to the current context), and an area known as the Outer Environment (which is null when in the Global Execution Context.


Hoisting

The Execution Context is created in two phases:

  1. Creation Phase - the following are set up:
    • Global Object
    • 'this' Variable
    • Outer Environment
    • Memory Allocations - variables are allocated with values of 'undefined'. Functions are allocated with full definitions.
  2. Execution Phase - the code is executed line-by-line, in order, in a sequential, single-threaded, synchronous manner.

So before the code is executed, the JavaScript engine has already set aside memory space for the variables and functions. Functions are placed in memory in their entirety, while the variables are set up with the placeholder called undefined. All variables are initially initialized as "undefined", while all functions are placed into memory in their entirety. So in the creation phase, all variables are set to "undefined" and all functions are fully defined in memory. This explains why the function executes in the code below, and the variable is printed with an 'undefined' value (instead of throwing an exception).

1
2
3
4
5
6
7
8
x();
console.log('y = ' + y);

var y = 'Some Text';

function x() {
	console.log('x executed');
}


Function Executed and Variable Contents Displayed Before Defined in Code

.Hosting - in the creation phase, all variables are set to "undefined" and all functions are fully defined in memory


Hosting - in the creation phase, all variables are set to "undefined" and all functions are fully defined in memory.

In JavaScript you invoke a function by putting the parenthesis after the function name (e.g. MyFunction() causes the function called MyFunction to execute). Each time a function is run, a new execution context is created and is placed on the execution stack, with the global execution stack being on the bottom of the stack. The new execution content completes phase one (allocation) and begins phase two (execution). If during execution it encounters another function call, then it stops and creates the execution context for the second function, and so on. When the last function finishes, its execution context is popped off the execution stack. Which ever execution context is currently on the top of the stack at any one time, is the execution context which is running. If a variable is defined and has the same same name in three different executions contexts, then the value of the variable depends upon the currently running context. That is, previously running executions contexts will have not effect on the value of the variable (Because a version of the variable is defined in each execution context).

However if a variable, in a function, is called in its execution context in which the variable was not defined (note, this is not the same as the keyword undefined. i.e. not defined means the variable memory was never allocated, where undefined means the variable memory was allocated but no value assigned to the variable), then the "Scope Chain" references the "outer environment" to find the variable. The "outer environment" is not necessarily the last execution context in the execution context stack, but is instead dependent upon where the the function defined in the code (i.e. its lexical environment). This is illustrated in the JavaScript below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function y() {
	console.log('theVar = ' + theVar);
}

function x() {
	var theVar = 2;
	y();
}

var theVar = 1;
x();


JavaScript Illustrating the Scope Chain of Variable Depends Upon its Lexical Environment

.Scope Chain of Variable Depends Upon its Lexical Environment


Scope Chain of Variable Depends Upon its Lexical Environment

When JavaScript tries to dereference a variable not defined within the current execution context, it looks in its "Outer Environment". In the example above, functions x and y are defined at the same level within the code, so both of their Outer Environments are at the base level. (i.e. they are both attached to the global object). However if function y had been coded inside function x, then the Outer Environment for function y would be function x, and the value of 2 would be printed.

  1. The execution context depends on when the functions are invoked.
  2. The outer environment depends on where the functions are written in the code (i.e. its lexical environment). Variable scope chains reference their outer environments for finding variables which are not defined (not allocated).


Asynchronous JavaScript Calls

The JavaScript engine is single threaded, synchronous. It executes one command at a time and waits for the command to finished before it executes the next command. How then does it work with Ajax to make asynchronous calls? The browser handles sending and receiving the HTTP requests and responses (not the JavaScript). JavaScript has an Event Queue where events are placed as they happen (e.g. button clicked, HTTP data received). When the execution context stack is empty, then JavaScript will examine the event queue and look for (i.e. "listens for") events which it has been told to handle. If such an event is found, a new execution context is created and the function handling the particular type of event is executed.

The JavaScript engine is continually checking the event queue (i.e. the event loop), and when the execution context stack is empty, it will look in the event queue for events it has been told to handle, and execute the function assigned as the event's handler. So in Ajax, JavaScript tells the browser to send the request and continues executing its code synchronously. When the browser receives the response from the server, it puts it in the event queue. When JavaScript finishes all of its current processing (the global execution stack is empty), it will find the response in the event queue and execute the function (i.e. call back function) assigned to handle the event. So the response from the server happens outside of the JavaScript engine, and the browser places the response in JavaScript event queue.


JavaScript uses Dynamic Typing

Strongly Typed (or Static Typed) languages (e.g. Java, C#) determine a variables data type when the code is compiled. If you try to assign an incorrect data type to a variable in a strongly typed language, a compiler error occurs. JavaScript uses dynamic typing to determine, or change a variable's data at run time. In strongly typed languages a variable is assigned a data type, and that data type can never be changed. In dynamic typed languages a variable can change its data type based upon the value it is assigned. A dynamic type variable may start out as a string and change to a number.

Note: C# uses the var keyword to allow the compiler to determine the variables data type. However once determined by the compiler, the type can not be changed.


JavaScript has Six Primitive Types

  1. undefined - a variable's memory space has been allocated, but no value has been stored in the variable. Set by the JavaScript engine during creation phase.
  2. null - a variable does not contain anything. Programmers should use null, instead of undefined to indicate no value exists in the variable.
  3. Boolean - "true" or "false"
  4. Number - a floating point number. The only numeric type in JavaScript (i.e. JavaScript does not have Integer, Decimal, etc. Types). Having only the one numeric data type can cause some odd mathematical calculations.
  5. String - both single and double quotes can be use.
  6. Symbol - new in the up coming version of EcmaScript 6.


JavaScript Operators

Operators are predefined functions that typically take two parameters (although single parameter operators exist (Unary) as do three parameter operators (Ternary) and return a value. Operator functions use infix notation (i.e. 1 + 2) as opposed the traditional prefix notation (i.e. + 1, 2) of functions. With JavaScript's dynamic typing, its operator precedence and associativity can sometimes not be readily apparent. Mozilla Developer Network has a good reference for JavaScript Operator Precedence. The reference chart shows the operator with the higher precedence (higher number on the chart) gets calls first. It also shows whether they have right-to-left or left-to-right associativity. Associativity matters when operators have the same precedence. Examples of JavaScript operator associativity and precedence are shown in the following statements:

1 + 2 * 3 = 7
(1+2) * 3 = 9

var x=1, y=2, z = 3
x=y=z (all three are equal to 3 because of equals right-to-left associativity).

JavaScript will convert a variable's data type depending upon the type of value it is assigned (Coercion). This is an aspect of dynamically typed languages, which can sometimes cause surprising results. Examples of coercion are:

var a = '1' + 2 => 12 (number coerced to a string)

3 true, because, with left associativity, it is really running (false

Number(undefined) => NaN (Can not manually coerce undefined to a number)
Number(null) => 0

1 == '1' => true
1 === '1' => false (because strict equality also checks data type, i.e. it does not try to coerce the values)
false == 0 > true
true == 1 > true
null == 0 => false (even though false coerces to 0)

more about coercion and equality can be found on the Mozilla Developer Network - Equality comparisons and sameness page.

Boolean(undefined) => false
Boolean(null) => false
Boolean("") => false
Boolean(0) => false

The above three coercions are typically used to check for existence, so the following can be used to check to see if a variable contains a non-zero value:

if (myVar) {
// Then myVar has a non-value.
}

To set a default string value, instead of letting coercion set a value of the string 'undefined':
use:

var name;
mvVar = name || 'My Name'; => 'My Name'; (Because || has a special behavior that returns the first value that can be coerced to true).

this can be useful when JavaScript libraries have name collisions, so to avoid use:

window.SomeVariable = window.SomeVariable || "My Variable Name"; (To keep from walking on SomeVariable which was already defined in another library).

Note: JavaScript does not have namespaces to avoid name collisions, so when libraries are combined names can be overwritten with the last loaded version. To avoid this, the variables can be put into containing objects.


Objects and Functions

JavaScript objects have properties and methods. Properties can be accessed two different ways:

  1. Computed Member Access a.ka. Magic Strings
  2. Member Access a.k.a. the Dot Operator (Preferred Method)
1
2
3
4
5
6
var customer = new Object();
customer["name"] = "Sam"; // Magic Strings
customer.name = "Sam"; // Dot Operator

customer.address = new Object();
customer.address.city = "Champaign";

JavaScript contains an Object Literal Syntax which allows you to define objects. The object literal var customer {}; is the same as var customer = new Object();. An object defined and initialized in object literal syntax looks like this:

1
2
3
4
5
6
7
var customer = {
     name: 'Joe'
     address: {
          city: 'Champaign',
          state: 'Illinois'
     }
}

Object literal syntax can be used to create an object as a parameter, inside a function call ... or any where you would use an object variable.


JavaScript Object Notation (JSON)

JSON is inspired by JavaScript's Object Literal Notation, but they are not quite the same as there are some syntax differences. JSON is a subset of Object Literal Notation syntax (All JSON is valid Object Literal Notation syntax, but not vice-versa). JSON has more strict requirements than JavaScript Object Literal syntax. JSON, being is more concise format that XML, has become a popular method for sending data across the Internet. However, because the two are so close, JavaScript does contain built in functions for converting between the two.

  1. JSON.Stringify - converts JavaScript object to JSON
  2. JSON.Parse - converts JSON string to a JavaScript object


JavaScript Functions are Objects

JavaScript has first class function (i.e. anything you can do with other types, you can do with functions). First class functions can change the way you program by providing new ways of solving problems (i.e. Functional Programming). You can attach properties, objects, and other functions to a function. Functions are objects whose code is also one of the properties of the functions of the object which is invocable. Below is an example of a function containing a property:

1
2
3
4
5
6
function speak() {
   console.log('My name is HAL');
}

speak.language = 'english';  // A property on the function
console.log(speak.language);


So JavaScript functions are more than just a container of code, they are objects.

expression - a unit of code that returns a value
statement - a unit of code that does not return a value, it just does work

1
2
3
4
5
6
7
8
9
// Function Statement (Named Function)
function speak() {
console.log('Arf');
}

// Function Expression (Anonymous Function) (results in a function object being creating)
var myGreet = function speak() {
console.log('Arf');
}


Note Function Statements can be run before their definitions, but Function Expressions can NOT. (Because the function expression is really a variable). Also anonymous function (function expressions) can be passed to other functions.


'this' Keyword

The 'this' keyword points to an object. Initially it points to the global object. Even when used inside a function, the 'this' keyword still points to the global object.However when a function is actually a method attached to an object, 'this' points to the containing object. This allows easy access to other properties and methods on the same object to which the method is attached.

However, many view it as a bug, that inside a nested subfunction, 'this' can point to the global object, instead of the containing object. As a work-around, set

var self = this;

as the first line in the function, then always use 'self' to point to the containing object. Note: the ES6 'LET' statement is meant to clear us some of these problems.


Arrays

Since JavaScript has dynamic typing, its arrays can contain different data types;

var arr [ 1, false, "hi", function(myVar) { console.log(myVar);}, {name: 'Joe'} ]; // JS Arrays can contain a combination of data types.

So this is a valid function call: arr[3](arr[5.Name]);


arguments Keyword

the arguments variable is automatically set up by the JavaScript engine and it contains a list of all the values that pass to a function. Instead of passing the parameters to a function, you can pass zero or more parameters without getting an error. You can also pass in no parameters but get the values from the arguments keyword. So JavaScript does not have a need for the "Function Overloading" used in other languages.

1
2
3
4
5
function speak(name1, name2, name3) {
     if (arguments.length !== 0) {
        console.log("name2 is: " + arguments[1]);
     }
}



Automatic Semicolon Insertion (Can Cause Logic Errors)

The JavaScript syntax parser will automatically insert semicolons where it believes they should be placed. So while semicolons are optional for the programmer, it is best for the programmer to always put in the semicolons manually to avoid 'hard to find' errors related to semi colons). This is why you frequently see the opening parenthesis on the same line as functions and if-statements in JavaScript. The example below shows that if the opening parenthesis on a return statement is put on the next line, the JavaScript syntax parser will insert a semicolon before the parenthesis, altering the intended logic.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function getWord() {
     return 
       {word: "play"}
}
console.log(getWord());  // Returns undefined


function getWord() {
     return {
	 word: "play"}
}
console.log(getWord());  // Returns object with the word property containing play



Immediately Invoked Function Expressions (IIFE)

IIFEs involve invoking the function (immediately) at the point it is created. IIFEs are created by wrapping the function inside parenthesis, to make it a function express, and then execute it by using (). Below is an example of an IIFE

1
2
3
4
// An IIFE
(function speak(word) {
     console.log('Word is: ' + ' ' + word);
}('Arf'));



Using an IIFE keeps all the code and variables within the same execution context. So it prevents code and variables from spilling over into other execution contexts where they could cause problems. Many JavaScript libraries wrap all their code into on large IIFE to isolate all the library code.


Function Closures

Function Closures are a automatic feature of the JavaScript language which can be used to create powerful coding patterns. Closures can be defined by examining the behavior of two functions. When function One finishes its execution, the execution context for function One is popped off the execution context stack. However the variables defined within function One still reside in memory at the level of at which function One existed. When function Two is invoked, and references a variable not defined in function Two, but was defined in function One, function Two will go down the scope chain to find the variable left over by Function One. Since Function Two can not find the variable definition, it goes to the Outer Environment to locate the variable. The Outer Environment includes references to the variable memory from previously run functions, so it is able to find the variables defined in a previously run function. This process, where the execution context has closed in its outer variables, is called Closure.

So whenever a function finishes and is removed from the execution context stack, JavaScript maintains a reference to the variable memory that was defined by the function. It is maintained at the same level as the finished function. So new functions can find these variables defined by previously executed functions, by going down the scope chain ... i.e. the execution context has closed in its outer variables. It is important to realize that the function closure for a new function contains only the outside variable memory from the functions which created it, not all functions which were executed after is was created. This is illustrated in the Function Factory example in the next section.

Below is the classic example used to illustrate JavaScript closures. Some people will guess the printed results will be 1,2,3, when actually the printed results are 3,3,3. This is analogous to asking three children the age of their father. The children will not give the age of their father when they were born. But will instead give the same answer, which is the age of their father today. What gets printed is the value of the variable at the time the function is invoked, not at the time the function was created. This can be difficult for people to understand who have only worked with languages which have block scoping. JavaScript does not have block scoping, but has access to Free Variables from previously executed functions. However in ES6, the LET keyword will introduce block scoping (for those variables defined with LET) into JavaScript.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Classic Example of a Closure
function buildFunctions() {
	
	var arr = [];
	
	// Put three functions inside array
	for (var i =0; i < 3; i++) {		
		arr.push(
		   function() {
		      console.log(i)	
		   }
		)
	}
	return arr;
}

var fs = buildFunctions();

fs[0](); // Prints: 3
fs[1](); // Prints: 3
fs[2](); // Prints: 3

// By the time the functions are invoked, variable i was set to 3
// during the process of creating the functions in buildFunctions.
// buildFunction is finished (i=3), then the three functions are invoked.


In the example above, to avoid using the Free Variables (variables outside the function that you can still access), and have it print 1,2,3, the anonymous function could be changed to an IIFE. The loop variable (i) would have to be passed in to the IIFE. Then the loop would store the results of the function in the array (instead of storing the function in the array).


Function Factories

Function Factories are functions which return functions. Closure can be used to specify different parameters for the created functions by linking functions to the outer environment used to create the function. This allows the function factory to create functions which behave differently, based on a parameter passed in when the function was created. Below is an example of a function factory.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Function Factory
function translateWord(language){
	
	return function (word) {
		
		if (language === 'es') {
			switch (word) {
				case 'red':
					alert('Spanish for red is: rojo');
					break;
				case 'green':
					alert('Spanish for green is: verde');
					break;
				default: 
					alert('Spanish translation unknown');
					break;
			}
		}
		
		if (language === 'fr') {
			switch (word) {
				case 'red':
					alert('French for red is: rouge');
					break;
				case 'green':
					alert('French for green is: vert');
					break;
				default: 
					alert('French translation unknown');
					break;
			}
		}
		
	}
	
}

// Create the functions
var translateSpanish = translateWord('es');
var translateFrench = translateWord('fr');

// Invoke the functions
translateSpanish('red');
translateFrench('red');


.Output of Function Created by Function Factory


Output of Function Created by Function Factory


Callbacks

An example of a built-in JavaScript function that uses closures is the setTimeout function. The setTimeout function waits for the specified time period and then drops and event into the event queue. When the listener finds the event, it executes the function assigned to handle the event (i.e. the function you passed in to setTimeout). In the example below, since setTImeout has finished execution, it does not know about the variable called "word", so it goes down the scope chain to find the function that created the function (speakTimer created the anonymous function which is executing) and locates the variable in that functions remaining memory space. So closure allows the anonymous function access to the "word" variable created in the speakTimer function, even though the speakTimer function has ended its execution.

The anonymous function passed into the setTimeout function is called a Callback Function. Callback Functions are really event handler functions passed to a function. The passed event handler function will execute when the event is put into the event queue. The event may be put into the queue at the end of the function's execution (as is the case with setTimeout), or it may be put into the event queue some time after the function has completed execution (as is the case when the browser drops an event in the queue notifying the arrival of data from the server, think Ajax).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function speakTimer(milliseconds) {
	
	var word = 'Yellow';
	
	setTimeout(function() {
		alert(word);
	},milliseconds);
	
}

speakTimer(5000);


setTimeout Function using a Callback Function