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 invocation – this 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)