JavaScript and JavaScript Tools - Client-Server Web Apps with JavaScript and Java (2014)

Client-Server Web Apps with JavaScript and Java (2014)

Chapter 2. JavaScript and JavaScript Tools

JavaScript is most despised because it isn’t SOME OTHER LANGUAGE. If you are good in SOME OTHER LANGUAGE and you have to program in an environment that only supports JavaScript, then you are forced to use JavaScript, and that is annoying. Most people in that situation don’t even bother to learn JavaScript first, and then they are surprised when JavaScript turns out to have significant differences from the SOME OTHER LANGUAGE they would rather be using, and that those differences matter.

—Douglas Crockford

Thus Douglas Crockford summarizes JavaScript as the language that many use but few learn. His book goes on to identify parts of the language that are legitimately useful and powerful and points out others that are truly problematic and best avoided. If you are a programmer required to extensively use JavaScript, it simply makes sense to take the time and energy to study it thoroughly. Crockford’s approach makes the programmer’s learning task more manageable by effectively ignoring large parts of the language and focusing on a powerful and concise subset.

In addition to learning JavaScript itself (later standardized under the name ECMAScript), you need to invest time learning about the specific programming environment. While other languages run on underlying operating systems, relational databases, or host applications, JavaScript was designed originally to run in a browser. The ECMAScript Language Specification explicitly states this.

ECMAScript was originally designed to be a Web scripting language, providing a mechanism to enliven Web pages in browsers and to perform server computation as part of a Web-based client-server architecture.

— ECMAScript Language Specification

The core JavaScript language needs to be understood in relation to two distinct APIs: the Browser Object Model (BOM) and the Document Object Model (DOM). The BOM consists of a window and its child objects: navigator, history, screen, location, and document. The document object is the root node of the DOM, a hierarchical tree representation of the contents of the page itself. Some of the complaints about JavaScript are actually due to issues with BOM or DOM implementations. Development of JavaScript in a web browser cannot be done effectively without a thorough understanding of these APIs.

The remainder of this chapter will introduce the main topics that need to be understood in a browser JavaScript development. It will not be exhaustive or comprehensive, but will highlight the necessary starting points and categories that you need to understand in order to develop an in-depth understanding of the language.

Learning JavaScript

The Java language has been widely adopted in educational settings. Developer certifications have been available for a number of years. There is therefore a well-understood, standardized, general, common body of knowledge associated with Java. Java is often learned first in the classroom, and professionals obtain certification after a fairly defined program of self-study. The same cannot be said of JavaScript, but there are a number of good books on JavaScript:

§ JavaScript: The Good Parts (O’Reilly), by Douglas Crockford, has been mentioned already. It has become fashionable in some circles to take issue with Crockford at various points, but that is because he is a recognized authority who has helped shape the thinking of many JavaScript developers. In some cases, he provides arguably overly strict “rules of thumb,” but you will do yourself a great disservice if you don’t understand the subset of the language he considers “the good parts” and the parts he avoids.

§ Secrets of the JavaScript Ninja (Manning Publications) is by John Resig and Bear Bibeault. John Resig is the author of jQuery and as such has a broad understanding of practical challenges related to browser compatibility and DOM implementations.

§ Several books are closer to standard language reference texts, including JavaScript: The Definitive Guide (O’Reilly) and Professional JavaScript for Web Development by Nicholas C. Zakas (Wrox Press). These are more comprehensive (and less opinionated) than the previous two books. They may not be the type of book you would read end to end, but they are invaluable for delving into specific topics.

This section will not attempt to replicate all that you can learn from these and other books, but will provide starting points for you to evaluate your own knowledge of JavaScript. Additional books and resources will be referenced throughout the chapter that you can consult if you encounter terms or concepts you want to research further.

CONSCIOUS COMPETENCE

A crucial step in the learning process is to be aware of what you know relative to what can be known. There is a documented cognitive bias known as the Dunning–Kruger effect. It describes a tendency for unskilled individuals to mistakenly rate their ability as much higher than average. Because of the confusion related to JavaScript and the frequency with which it is dismissed as a “toy language,” the goal of this section (related to the “conscious competence” learning model) is to raise awareness of what there is to learn.

JavaScript History

The history of JavaScript is well documented, originating with Brendan Eich writing the initial version in 10 days in 1995. But it is instructive to consider JavaScript in light of earlier computer science history, especially in relation to Lisp, the second-oldest high-level programming language in existence. Lisp was invented by John McCarthy in 1958 (one year after Fortran) as a practical mathematical notation for computer programs. Scheme is one of the two main dialects of Lisp. Strangely enough, Scheme plays a significant part in JavaScript’s history despite being a stark contrast in language design. Figure 2-1 illustrates some of the significant programming languages that influenced the design of JavaScript.

The simple, minimalist design philosophy of Scheme is not at all evident in JavaScript. Its relative verbosity is based in influences from other languages cited in the JavaScript 1.1 Specification:

JavaScript borrows most of its syntax from Java, but also inherits from Awk and Perl, with some indirect influence from Self in its object prototype system.

— JavaScript 1.1 Specification

JavaScript Syntax Influences

Figure 2-1. JavaScript syntax influences

This is quite a contrast to Scheme, which does not have several different languages informing its syntax. Perl directly influenced parts of JavaScript, such as regular expressions support. Perhaps the Perl motto TMTOWTDI (“there’s more than one way to do it”) influenced JavaScript in a broader way as well. At least it can be said that the converse, “there’s only one way to do it” (popular among the Python community) does not apply. Consider the variations available to create and initialize an array:

var colors1 = [];

colors1[0] = "red";

colors1[1] = "orange";

var colors2 = ["yellow", "green", "blue"];

var colors3 = new Array(2);

colors3[0] = "indigo";

colors3[1] = "violet";

var colors4 = new Array();

colors4[0] = "black";

colors4[1] = "white";

Therefore, it might appear that any connection between JavaScript (with its many influences and syntactical variations) and Scheme (a minimalistic dialect of Lisp) seems unlikely. As it turns out, JavaScript’s heritage does include close connections with and direct influences from Scheme:

As I’ve often said, and as others at Netscape can confirm, I was recruited to Netscape with the promise of “doing Scheme in the browser.”

— Brendan Eich

This is also reflected in the ECMAScript Language Specification:

Some of the facilities of ECMAScript are similar to those used in other programming languages; in particular Java, Self, and Scheme.

— ECMAScript Language Specification

The influence has been recognized by others. Douglas Crockford wrote the “The Little JavaScripter” based on the classic by Daniel Paul Friedman called The Little Schemer (MIT Press), which illustrates commonalities between Scheme and JavaScript. The Lisp community itself (as represented by the European Lisp Symposium) describes ECMAScript as a “dialect of Lisp.” There are undeniable similarities between JavaScript and Scheme that are due to the intentions of its creator.

A Functional Language

Java developers tend to approach programming problems from an object-oriented perspective. Although JavaScript can support object-oriented programming of a sort, it is generally not the most productive way to approach problems. It is far more productive to leverage JavaScript’s functional capabilities. An understanding of what this means and its implications clarifies the nature and power of the language.

The primary trait of JavaScript that makes it like Scheme, as it relates to both its origin and syntax, is that is in a functional language. Functional language here is used to indicate a language that supports functional programming and first-class functions. This fundamental concept of JavaScript provides an orientation about other aspects of the language. Adoption of functional programming entails a significant paradigm shift for many programmers, especially those grounded in a language like Java that does not (yet) directly support it.[1]

Scope

Scope, the portion of a program in which a variable is visible and operative is a rather slippery subject as implemented in JavaScript. Like many other languages, a function is used to enclose a set of statements. This allows functions to be reused and limits the visibility of information to a well-understood modular unit. There are three execution contexts defined in the ECMAScript Language Specification: global, eval, and function. JavaScript has function-level scope rather than block-level scope like other C-like languages. Blocks such as those used by if statements and other language constructs do not create a new scope.

One danger in JavaScript is that a method or variable might be hoisted or moved to top of scope where it is defined. Since a function declaration is already available at the moment of the scope’s execution, the function appears to be hoisted to the top of the context. A rule of thumb to avoid the issue is to use a single var statement at the top scope to declare all variables that will be needed within that scope:

//this is not like an instance variable in java...

var x = 'set';

var y = function () {

// WHAT YOU DON'T SEE -> var x; is effectively "hoisted" to this line!

if (!x) { // You might expect the variable to be

// populated at this point...it is not

// though, so this block executes

var x = 'hoisted';

}

alert(x);

}

//... and this call causes an alert to display "hoisted"

y();

The hoisting example includes a few other features that do not exist in Java:

§ In JavaScript, null, undefined, and a few other values evaluate to false.

§ The if conditional expression is !x. The exclamation point is a NOT logical operator. Therefore, if x is undefined (or null), this expression if (!x) evaluates to true. If x had contained a value such as a number or a string at this point, it would have evaluated to false, which is what a developer from another language is likely to expect.

§ The var keyword is used to define a local variable. Variables declared without it are global. This definition results in the variable being associated with the scope of the function.

§ A function is being created and assigned to a variable named y. This is particularly strange to Java programmers who deal with methods that only exist attached to a class or object instance. This syntax calls attention to the functional nature of JavaScript.

First-Class Functions

Simply having scope-limiting functions available in a language does not make it a “functional” language in any strict sense. A functional language supports first-class functions. According to the Structure and Interpretation of Computer Programs, first-class functions can be named as variables, passed in and returned as results of functions, and included in data structures. The following (contrived) example illustrates these features as well as another characteristic that some researchers cite as a requirement for functional languages: support for anonymous functions:

//

// The following example can be run in a

// modern browser at the JavaScript console

//

// Assigning a function to a variable

var happy = function(){

return ':)';

}

var sad = function(){

return ':(';

}

// A function that will be used to receive a

// function as an argument and return it as well.

var mood = function(aFunction){

return aFunction

}

// Functions added to data structures, arrays:

list = [happy, sad]

//...JavaScript objects

response = {fine: happy, underTheWeather: sad}

// A function can be passed in as an argument,

// returned as a result of a function call

// and assigned to a variable

var iAmFeeling = mood(happy);

console.log(iAmFeeling());

// Try it again

var iAmFeeling = mood(sad);

console.log(iAmFeeling());

// A function can also be included in data structures;

// in this case, a JavaScript object.

console.log(response.fine());

// - or if you prefer an array...

console.log(list[0]());

// Finally, an immediate, anonymous function.

console.log(function(){

return ";)";

}());

So as is apparent from this example, functions are fundamental units in JavaScript and are in fact “first-class.” They can stand alone and are not required to be included in an object or other construct. They can appear anywhere an expression can. The property that distinguishes a function from other types of JavaScript objects is the fact that it can be invoked. Terse, compact code can be written because functions are first class and primary modular units of execution. The fact that scope is related to functions has implications for JavaScript idioms that are unfamiliar to many new JavaScript developers.

IS JAVASCRIPT REALLY FUNCTIONAL?

Some question whether JavaScript qualifies as a functional language. After all, functional programming is supposed to mimic mathematical functions, which are free of side effects. Anyone who worked with JavaScript has dealt with its notorious global context, and most likely encountered side-effect-laden functions when wrangling the DOM. This hardly qualifies as referential transparency. On the contrary, much JavaScript programming involves an acute awareness of the surrounding environment. Besides, variables are, well, variable. Purely functional languages utilize immutable variables (which provide various benefits such as ease in implementing concurrent operations).

In addition, JavaScript does have objects and prototypical inheritance. It could arguably be classified as object oriented or at least multiparadigm.

What is beyond argument is that JavaScript does indeed include functional constructs and supports first-class functions. So you can choose a definition for “functional language” (since there does not appear to be an authoritative definition) and make up your mind whether JavaScript qualifies in a theoretical sense for this designation. The reason for using it in this book is that it aligns JavaScript with languages and techniques that highlight the features and best qualities of the language. For a much more in-depth look at the language from this perspective, see Functional JavaScript by Michael Fogus (O’Reilly) which introduces a wide range of functional techniques implemented in JavaScript, many using the excellent underscore.js library.

Function Declarations and Expressions

A JavaScript function literal consists of four parts:

§ The function operator

§ An optional name

§ Open and close parentheses (optionally containing one or more parameter names)

§ Open and close brackets (optionally containing one or more statements)

A valid minimal JavaScript function declaration statement is as follows:

function(){}

A function can also be given a name, which leads to a style that looks a bit more like traditional C-language family syntax:

function myFunctionName(){}

If a function does not have a name, it is said to be anonymous. An anonymous function can be used in an expression and assigned to a variable. Some authors prefer this syntax to declaring a named function because it makes it clear that a variable contains a function value:

var x = function () {}

It is also possible to assign a named function to a variable:

var x = function y() {}

The practical use of this named function expression is that while the function is available from the outside through the variable x, it is also available from inside the function itself (in a recursive call) as y.

Functions can be attached to objects and then are referred to as methods. A method is implicitly passed the object that called it. It can access and manipulate data that is contained within the object. The object is referred to using the this keyword as illustrated here:

var obj = {}; // Create a new JavaScript object

obj.myVar = 'data associated with an object'

obj.myFunc= function(){return 'I can access ' + this.myVar;} // this: the object

console.log(obj.myFunc())

A function can be defined inside of another function, where it also can access variables of the function that encloses it. A closure occurs when a function returns an inner function. The returned object includes the function itself as well as its environment when it was created:

function outer() {

var val = "I am in outer space";

function inner() {

return val;

}

return inner;

}

var alien = outer();

console.log(alien());

An immediate function is a way to limit code to a local functions scope so as to avoid polluting the global scope:

(function() {console.log('in an immediate function')}());

Function Invocations

There are four ways to call a function:

§ As a function

§ As a method

§ As a constructor

§ Using call() or apply() methods

The chosen method affects what the this keyword references. In the first option (as a function), this references the global context when not in strict mode. In strict mode, undefined or the value assigned in the execution context is returned. The second two (method and constructor) are specific to an object-oriented approach. A method invocation involves a call to a function that is attached to an object. A call to a constructor causes a new object to be created. Unlike the first three options, the call and apply methods allow you to explicitly set the context when you invoke them on a function.

THIS AND THAT

A JavaScript convention that can be a bit baffling at first glance is:

var that = this

This usage is obvious once you understand the way this works in JavaScript. Because this can vary based on context (scope), some developers alias it to that as a way to retain access to the original value of this.

Function Arguments

As previously mentioned, each function can receive arguments through named parameters in the function signature. There is a special variable named arguments that can hold any and all variables passed to a function whether they are named or not. The following examples demonstrate how to add three numbers using a standard function call and also using a function’s apply and call methods:

function add(){

var sum=0;

for (i=0; i< arguments.length; i++){

sum+=arguments[i];

}

return sum;

}

console.log(add(1,2,3));

console.log(add.apply(null, [2,3,4]));

console.log(add.call(null,3,4,5));

Objects

In Java, an object is created as an instance of a defined class. In JavaScript, an object is simply a collection of properties. JavaScript objects do inherit (from a prototype object) and so object-oriented design principles are applicable. But the differences from Java’s classical approach are significant. JavaScript allows for the creation of classes, but it is not useful to think about them in the same way as you would in Java (where classes are required and fundamental).

Classical and prototypical inheritance differentiates Java and JavaScript and results in confusion due to their differences. Other features of JavaScript can be highlighted by contrasting it with Java.

JavaScript for Java Developers

Most developers realize that JavaScript syntax superficially resembles that of Java or other C-based language (for loops, conditional statements, and so on). But when full Java applications are viewed, the differences become immediately evident. The following are well-known basic Java programs that illustrate differences in JavaScript code and development practices.

HelloWorld.java

/**

* HelloWorld

*/

class HelloWorld{

public static void main (String args[]){

System.out.println("Hello World!");

}

}

To see the venerable Hello World example program in action at the command line, you need to:

1. Create a source file named HelloWorld.java.

2. Compile the Java code into a class file (using the Java Compiler via the javac command).

3. Execute the resulting class file (using the Java interpreter via the java command).

If you use an integrated development environment like Eclipse or IntelliJ, these steps are represented by corresponding menu options. Simply enough, the program prints out the string literal “Hello World!” when executed. But this simple program serves to highlight a number of significant differences between Java and JavaScript.

The following is the comparable JavaScript program that produces the same output:

console.log('Hello World')

Program execution

First of all, JavaScript is an interpreted language. No compilation is necessary. The execution environment for JavaScript immediately comes into question. If you have node installed, you can run this at the node prompt:

> console.log("Hello World")

Hello World

This code can be executed at a browser console. In Chrome, select View → Developer → JavaScript Console (see Figure 2-2).

Chrome JavaScript console

Figure 2-2. Chrome JavaScript console

In Firefox, select Tools → Web Developer → Web Console (see Figure 2-3).

Firefox JavaScript console

Figure 2-3. Firefox JavaScript console

Other modern browsers have comparable menu options that provide the same functionality.

HOST OBJECTS

Technically, there is no built-in I/O functionality in JavaScript (although the runtime environment—in this case, the browser—does provide it). This is in accordance with the ECMA standard:

ECMAScript as defined here is not intended to be computationally self-sufficient; indeed, there are no provisions in this specification for input of external data or output of computed results. Instead, it is expected that the computational environment of an ECMAScript program will provide not only the objects and other facilities described in this specification but also certain environment-specific host objects, whose description and behavior are beyond the scope of this specification except to indicate that they may provide certain properties that can be accessed and certain functions that can be called from an ECMAScript program.

The implications of this not being defined are more than a mere curiosity, not the least of which that console.log is not available in certain versions of Microsoft’s Internet Explorer and consequently, unexpected errors can occur. Many of the challenges and problems associated with the JavaScript programming language are actually the fault of the execution environment (which is often a web browser). The DOM is a cross-platform, language-independent means of referencing and manipulating HTML elements. It also is not part of the JavaScript language itself.

Back to the the Hello World example itself: you might have noticed that single quotes were used instead of double quotes and that there was no trailing semicolon. JavaScript syntax is forgiving (or ambiguous, if you prefer). There have been a number of innovations to reduce confusion in this area. A “strict” mode was added to the language itself. Utilities like Douglas Crockford’s JSLint were created to enforce the use of the “good parts” of the JavaScript language. See his book on the subject for more in-depth coverage. Suffice it to say, JavaScript has a number of leniencies that can result in an undisciplined developer or team causing some difficult-to-debug problems. It is well worth the time to learn the language well enough to adopt conventions and practices that avoid these problems.

File system organization

The file and directory structure of a Java project are directly linked to the structure of the code. A source file generally contains a single (public) class with the same name as the file. The file exists in a directory that reflects the package name associated with the class. (There are a few other rules and exceptions related to inner classes, access modifiers, and other constructs, but it is clear that file and directory structures will follow similar general structures across Java projects). At times, these restrictions can be an inconvenience (especially in small applications). As a project grows, it provides an clear indication of the general scope and organization of the code base. A glance at the file system makes it immediately evident when a project is becoming disorganized without ever opening a file.

JavaScript enforces no such restrictions. There is no necessary connection between file or directory structures. And so, you need to give particular attention to the organization of your code as a project grows, and will likely need to invest time in refactoring it if a larger development team is involved. Alex MacCaw explains this well in JavaScript Web Applications (O’Reilly):

The secret to making large JavaScript applications is to not make large JavaScript applications. Instead you should decouple your application into a series of fairly independent components. The mistake developers often make is creating applications with a lot of interdependency, with huge linear JavaScript files generating a slew of HTML tags. These sorts of applications are difficult to maintain and extend, and so they should be avoided at all costs.

— Alex MacCaw

Other aspects of code organization need to be considered as well. Besides naming files and intelligently including code in the proper file, dependencies between files require that they be loaded in a specific order. And when JavaScript is being served from a web server, efficiencies can be gained by loading a given file when it is actually needed (rather than causing a browser to hang while all of the files are downloaded). Performance gains can be accomplished utilizing the Asynchronous Module Definition (AMD) API, supported by libraries like RequireJS. This API allows module definition that lets the module and its dependencies be loaded asynchronously.

HelloWorld.java (with Variables)

The typical next step in demonstrating a Hello World application is to make it greet a specified party by the name specified in a variable:

/**

* HelloWorld2

*/

class HelloWorld2 {

public static void main (String args[]) {

String name;

System.out.println("Hello " + name);

}

}

This code will not compile:

HelloWorld2.java:5: variable name might not have been initialized

var name;

console.log('Hello ' + name);

This code will run in JavaScript, which leads to another source of confusion: too many bottom values that evaluate to false. The way that they are evaluated that can be confusing and difficult to remember:

// All evaluate to false

console.log(false ? 'true' : 'false');

console.log(0 ? 'true' : 'false');

console.log(NaN ? 'true' : 'false');

console.log('' ? 'true' : 'false');

console.log(null ? 'true' : 'false');

console.log(undefined ? 'true' : 'false');

All other values evaluate to true:

// All Evaluate to true

console.log('0' ? 'true' : 'false');

console.log('false' ? 'true' : 'false');

console.log([] ? 'true' : 'false');

console.log({} ? 'true' : 'false');

So after we initialize the variable in Java, the program compiles and runs:

/**

* HelloWorld2

*/

class HelloWorld2{

public static void main (String args[]){

String name = "Java";

System.out.println("Hello " + name);

}

}

Likewise, if we assign a value to our variable in JavaScript, we see the result printed out as expected:

var name='JavaScript';

console.log('Hello ' + name)

The var keyword is not required, and if you are in the global scope, it will not produce any difference in behavior. If called within a function, then var will create a local variable. So in general, variables should be declared within a function and declared with the var keyword to prevent pollution of the global namespace.

The Java example required that the type of the variable be declared. JavaScript is loosely typed and has no such requirement. The typeof operator can be used to illustrate the most common types. See Table 2-1 for examples.

Table 2-1. JavaScript typeof operator examples

Type

Result

Example

Undefined

“undefined”

typeof undefined

Null

“object”

typeof null

Boolean

“boolean”

typeof true

Number

“number”

typeof 123

String

“string”

typeof "hello"

Function object

“function”

typeof function(){}

Development Best Practices

JavaScript has its own set of unique challenges and characteristics that demand a unique development process. Although we can shoehorn a lot of JavaScript development into familiar Java processes, it is much more fitting to use specialized tools and procedures that are uniquely fitted to it.

Coding Style and Conventions

Much of the book is concerned with the loose coupling of client and server tiers. Unobtrusive JavaScript is the practice that establishes loose coupling of UI layers within the client application:

§ HTML defines the data structure of the page.

§ CSS applies design styles to the data structure.

§ JavaScript provides interactive functionality for the page.

Otherwise stated:

§ Avoid JavaScript in CSS.

§ Avoid CSS in JavaScript.

§ Avoid JavaScript in HTML.

§ Avoid HTML in JavaScript.

Browsers for Development

The browser is a piece of software so ubiquitous that many web users don’t even know that it is distinct from the underlying operating system. The browser is not only the environment in which an end user views a web page, the browser is an IDE. Browsers now include integrated debuggers, code formatters, profilers, and a plethora of other tools (some available as plug-ins or add-ons) that can be used during the development process.

Firefox (along with Firebug and other developer add-ons and extensions) has been popular for development for some time. Chrome has bundled developer tools and has gained popularity more recently.

CHROME TIPS

It is worthwhile to investigate the developer tools available on your browser and the command-line options that can influence the behavior of the browser. These generally bypass certain security constraints or performance optimizations for the sake of developer access and increased productivity. For instance, in Chrome:

§ There are certain settings such as clearing the browser cache that can prevent confusion when swapping out changes.

§ Command-line syntax varies between browser versions and operating systems. For example, Chrome can be run on OS X by running:

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome

Running at the command line allows you to include flags that alter browser behavior. If you are including files using Ajax (for example using AngularJS), --allow-file-access-from-files allows for development outside of a web server. And if you are using JSONP referencing your local machine (localhost) --disable-web-security is required.

There are a number of other somewhat hidden features in Chrome. Enter chrome://chrome-urls/ in the URL bar to get a listing of URLs that can be entered to access screens to configure or monitor activity. To whet your appetite, try out chrome://flags/ which reveals a list of experimental features available to the current version of the browser.

Another implication of browsers as the JavaScript environment are the emergence of online collaborative JavaScript development sites like JSFiddle and jsbin. These sites allow you to create example applications that replicate bugs, and communicate in rather exact terms with others about specific language questions. There is little reason to struggle with snippets of out-of-context code in JavaScript. It is the norm to provide specific examples and to code up small demonstrations when asking questions or demonstrating techniques online.

Integrated Development Environments

WebStorm is a particularly good IDE that is fast and lightweight and includes debuggers, a great project view, powerful shortcuts, extensibility via plug-ins and a host of other features. While not strictly necessary, WebStorm captures a lot of best practices through the use of wizards, shortcuts, and code completion.

Unit Testing

There are a number of unit testing frameworks that have been developed for JavaScript. Jasmine is a Behavior-Driven Development framework with no dependencies and a simple syntax that will be used in this book.

Java unit tests can be executed each time a project is built by the build tool or script. JavaScript can use a node module (Karma, which was formerly known as Testacular) to execute unit tests on a variety of different browsers each time a source code file is changed and saved! This is really worth noting. If you are disciplined about your creation of unit tests, the ability to run them all each time a source file is saved can result in early identification of otherwise obscure bugs. This is especially valuable when working with languages like JavaScript that do not use a compiler to perform initial code validation. Frequent, effective unit tests serve as a sort of pseudo-compiler. They provide immediate feedback regarding the quality of the code and catch certain bugs as soon as they are introduced.

Documentation

There are a few different automatic documentation generation options in JavaScript. Jsdoc is similar to Javadoc in its markup and output. Dox is a node module for document generation.

Literate programming (introduced by Donald Knuth in the 1970s) strives to enable programmers to develop programs in the order demanded by the logic and flow of their thoughts. Docco is a node module that incorporates comments presented in parallel to source code in a form much like the text of an essay. Although Docco does not directly validate or enforce code conventions, its presence and use can encourage thoughtful commenting and structuring of code instead of knee-jerk copy-and-paste exercises.

Project

This project is a small object hierarchy in JavaScript and includes tests and documentation. All files can be found on GitHub.

Animal.js is at the root of our object hierarchy:

// Animal is the top of the object hierarchy

function Animal() {}

// Define a speak function that have specific implementations in subclasses

Animal.prototype.speak = function() {

return "Animal is speaking.";

};

It has two subclasses, Cat.js:

// Define the Cat

function Cat() {

Animal.call(this);

}

// Set the object's prototype

Cat.prototype = new Animal();

// Name the constructor in a manner to suit the class

Cat.prototype.constructor = Cat;

// Create a class-specific implementation

Cat.prototype.speak = function(){

return "meow";

}

and Dog.js:

// Define the Dog class

function Dog() {

Animal.call(this); // Call the parent constructor

}

// Dog inherits from Animal

Dog.prototype = new Animal();

// Update the constructor to match the new class

Dog.prototype.constructor = Dog;

// Replace the speak method

Dog.prototype.speak = function(){

return "woof";

}

The latest version of Jasmine is available on GitHub:

curl -L \

https://github.com/downloads/pivotal/jasmine/jasmine-standalone-1.3.1.zip \

-o jasmine.zip

A test specification that includes a test for each of the classes defined in the preceding code is run by Jasmine:

// Animal Test using beforeEach

describe("Animal", function() {

beforeEach(function() {

animal = new Animal();

});

it("should be able to speak", function() {

expect(animal.speak()).toEqual("Animal is speaking.");

});

});

// Dog inherits from Animal and overrides the speak method.

// A function scoped variable is used for testing.

describe("Dog", function() {

it("should be able to speak", function() {

var dog = new Dog();

expect(dog.speak()).toEqual("woof");

});

});

// A bit more terse: a cat that inherits from Animal.

// Object constructor called in the same line as the speak method.

describe("Cat", function() {

it("should be able to speak", function() {

expect((new Cat()).speak()).toEqual("meow");

});

});

The simplest way to see this in action is to open SpecRunner.html in a browser, as shown in Figure 2-4.

Jasmine run example

Figure 2-4. Jasmine run example

To run the tests each time a file is changed, you will need an installation of node.js. You can verify your installation by checking the version of node installed:

node --version

v0.8.15

You should also have node package manager installed:

npm --version

1.1.66

With these installed, you can install Karma:

npm install karma

Once installed, you can view the help:

karma --help

The project configuration file was initially created using the init option. This created a file named karma.conf.js that can then be edited to reference applicable JavaScript files and run in installed browsers. Once configured, tests can be run every time a file changes by using the startoption.

Use npm to install the docco module used to generate documentation:

npm install docco

Run the docco command to create HTML documentation in the docs directory. Figure 2-5 shows one of the generated files. The comments are on the left, and syntax-highlighted code is on the right. You can access documentation for other files by choosing the file in the “Jump to” drop-down on the upper-right corner:

docco app/*.js

INSTALLING PYGMENTS

If you see the message “Could not use Pygments to highlight the source,” this is referring to a Python syntax highlighter called Pygments.

On a Mac or Linux machine, you can install it by running:

sudo easy_install pygments

This gives a quick overview of the caliber of development support now available for JavaScript. By adopting a few of these tools, the quality and maintainability of your code will be greatly enhanced.

Docco screenshot

Figure 2-5. Docco screenshot

This chapter really only scratched the surface of this sophisticated and ubiquitous language. Other books delve deeper into the subjects introduced here. For instance, JavaScript Web Applications by Alex McCaw (O’Reilly) demonstrates the use of certain established patterns (Model-View-Controller) and techniques related to building larger-scale JavaScript applications. Maintainable JavaScript by Nicholas C. Zakas (O’Reilly) helps deal with the undeniable challenge of establishing practices and standards that promote a maintainable and extensible codebase. And of course many resources are available online, through sites like the Mozilla Developer Network and StackOverflow.

JavaScript is most certainly not Java. It is a language all its own with a burgeoning eco-system of projects to support its development. A knowledge of the language itself and the development tools available will provide you with a good foundation as you explore the many frameworks and libraries that will be subsequently introduced.


[1] Functional programming has been available for some time on the JVM via scripting language support in several languages, including the Rhino JavaScript implementation. Lambda expressions for the Java programming language are slated for Java 8 and will add closures and related features to the language. Java 8 will also add support for a new JavaScript implementation known as Nashorn. So based on the features being added to the language, JavaScript development in general and functional programming in particular will be areas that Java developers will be expected to understand to a greater degree in coming years.