JavaScript – The Good Parts

By Douglas Crockford

The Good Ideas

  • Functions
  • Loose typing
  • Dynamic objects
  • Expressive object literal notation
  • “It is Lisp in C’s clothing, and this makes JS a remarkably powerful language” – Crockford

The Bad Ideas

Items in red highlight language design errors

  • Programming model based on global variables
    • All of the top-level variables of all compilation units (each <script> tag) are tossed together in a common namespace called the global object.
    • These units are compiled and immediately executed (JS puts them all into the global namespace)
    • window – browser’s global object name ( window.someVar = someValue; is globally accessible)
  • “JS’s popularity is almost completely independent of its qualities as a programming language” – Crockford

Core

  • JS is a prototype-based scripting language supporting OOP, imperative, & functional programming styles

  • Prototypal inheritance - OOP style where behavior reuse occurs via object cloning (clone as prototype)

  • Compilation Unit- Each <script> tag

  • Strong typing vs. Loose Typing

    • Crockford argues a large amount of testing is necessary anyway (compiler finds errors)
    • Loose Typing is less legible
  • JSLint is a JS parser that can analyze a JS program and reports on the bad parts that it contains.

Grammar – The Structure of Language

  • Only use line-ending comments // as block comments /**/ can be found in regular expressions in JS
  • undefined, NaN, Infinity are not reserved words but should have been
  • JS has a single number type: number – it is a 64-bit floating point that is the same as Java’s double
  • NaN is a number value that is the result of an operation that cannot produce a normal result
  • NaN is not equal to any value including itself (NaN === NaN; //false)
  • NaN can be detected via isNaN(number/operation)
  • \ is the escape character and it allows for inserting characters into strings that are not normally permitted
  • =, == and !=, === and !== (the various equality operators)
  • = assignment
  • == and != type coercion comparison (if not the same type buggy coercion occurs - DON’T USE)
  • === and !== strict comparison(same type and same value)
  • ++ -- DON'T USE (instead use += 1 or -=1 )
  • Strings are immutable (can never be changed) but a new string can be made via concatenation
  • private variables – a var used in a function is private to the function (function scope), but the various blocks within the function don’t create a new scope. (Hoisting occurs as well)
  • Hoisting –vars of a function are “hoisted” to the top and set to undefined (best practice, set vars at top)
  • When using return , you must have the object or value on the same line
    • Due to JS’s Auto__Semicolon Insertion a ’ ;’ will be placed after the return , returning undefined
  • typeof
    • typeof array returns ‘object’ instead of ‘array’
    • typeof null returns ‘object’ instead of ‘null’
    • typeof NaN === ‘number’ returns true
  • Falsy values include… (all other values are truthy including ‘false’ , true , and all objects)
    • false, null, undefined, ‘’ (empty string), 0 (zero), NaN
  • Names of object literals are not variable names, so they must be known at compile time
  • A function literal defines a function value which can…
    • Have an optional name (to call itself recursively)
    • Specify a list of parameters that will act as variables initialized by the invocation arguments

Objects

  • Object – is a mutable keyed collection that is a container of properties
    • A property name can be any string, including the empty string (lame)
    • A property value can be any JS value except undefined
    • Objects can have nested objects
  • A new object can be created in 4 different ways
    • Object literal (both work latter is best practice)
      • var obj = {“name”: “My Name”, “id”: “1”};
      • var obj = {name: “My Name”, id: “1”};
    • Pseudoclassical constructor using the new prefix (NOT recommended)
    • Call any function that returns an object
    • Using Object.create
      • When you make a new object you can select the object that should be its prototype by augmenting a create method to JS’s base Object (prototypal function creation).
      • If(typeOf Object.create !== ‘function’) {Object.create = function(o){var F = function(){}; F.prototype = o; return new F();};}
  • Object Retrival (both work, the latter is best practice)
    • customObject[“customVar”]
    • customObject.customVar
  • Update – a new value replaces an old property value if it exists, otherwise it is augmented into the object
  • Every object is linked to a prototype object. Objects created from literals are linked to Object.prototype
    • Dynamically adding properties to a prototype ensures the property is immediately available to objects that are based on that prototype
  • It is good practice to create a single global variable for your application (helps minimize global conflicts)
    • var MYAPP = {}; - Then MYAPP becomes the container for our application (and the namespace).

Functions

  • Functions are objects that can be stored in variables, objects, and arrays; and they can be passed as arguments, and returned from functions. They can even have methods.
  • There are two ways to declare a function
    • Function Expression - function definition assigned to a var (declaration only is hoisted)
    • Function Statement – function definition defined alone (entire statement is hoisted)
  • Function literal – var func = function(){//}; is an example of a Function Expression (best practice)
  • If a function lacks a name it is said to be anonymous
  • Closure – a practice where the local variables for a function are kept alive, even after the function has returned, so that the methods inside it can still reference the vars
  • Functions receive the parameters this and arguments in addition to their declared parameters
    • Due to a design error, arguments isn’t really an array, but an array-like object (w/a length prop)
  • this is defined by the invocation pattern (there are four)
  • Method invocation – methods use this to access the object it is in
  • Function invocationthis is bound to the global object (when a function is not part of an object)
  • Constructor invocation – functions that are intended to be used with the new prefix are constructors, by convention they are kept in vars with a capitalized name
    • Use of constructor functions is NOT recommended
  • Apply invocation – using the apply method lets us construct an array of arguments to use to invoke a function
  • A function always returns a value ( undefined is returned if a return value isn’t specified)
  • Augmenting – adds functionality to the prototype of an object, (objects of that prototype now have it)
    • By augmenting Function.prototype we can make a method available to all functions (powerful)
  • Module – is a function that defines private variables and functions, creates privileged functions which, through closure, will have access to the private variables and functions; and that returns the privileged functions or stores them in an accessible place
  • Best Private/Public Patterns
    • Revealing Module Pattern – is a best practice for attaining public and private scope
    • Self-Executing Anonymous Function – is a best practice for attaining public and private scope (common pattern used in libraries and widgets) enabling your library/code to grow via the window.namespace = window.namespace || {} technique
  • Cascading – achieved by having methods return the this object of the executing function (jQuery chaining)
  • Memoization – an optimization where functions use objects to retain the results of previous operations

Inheritance

  • Object Specifiers – write an object to pass to a constructor as opposed to a list or parameters and have the object define the parameters. Ex. var obj = maker( {first: f, middle: m, last: l} );
    • This style also benefits using JSON as an object can be passed to a constructor
    • Include any number of arguments (not all have to be passed) if the constructor is “smart”
  • Prototypal Inheritance – use the Object.create method (Objects Section)
  • Functional Inheritance – utilizes a function that produces objects, augments its objects, and utilizes closures to provide superior encapsulation vs. Prototypal Inheritance and access to super methods

Arrays

  • Array – linear allocation of memory where elements are accessed by integers (JS doesn’t have this)
    • Instead it has an object w/array-like characteristics
      • It converts array subscripts into strings that are used to make properties
      • It is slower than a real array (but can be more convenient to use)
      • Can contain any number of different ‘types’
      • It has integer property names. Ex. “0”, “1”, etc.
        • Array literal = var arr = []; (inherits from Array.prototype)
  • .length – is equal to the largest integer property name in the array plus one (not necessarily the number of properties in the array)
  • The length can be set explicitly, numbers.length = 3;
  • A new element can be appended via numbers.push(‘something’);
  • Use for loops (traverse in order) vs. for in loops (not guaranteed to traverse in order)
  • Use an array when property names are small sequential integers, otherwise use an object
  • Methods for arrays are functions stored in Array.prototype
  • A multi-dimensional array is simply an array of arrays (matrix)

Regular Expressions

  • Regular expressions – are used with methods to search, extract, and replace strings
    • They often carry a significant performance advantage over equivalent string operations
    • In JS they don’t allow comments or whitespace (poor for readability)