This is my summary of the (JavaScript: The Good Parts By Douglas Crockford)[http://shop.oreilly.com/product/9780596517748.do]. I use it while learning and as quick reference. It is not intended to be an standalone substitution of the book so if you really want to learn the concepts here presented, buy and read the book and use this repository as a reference and guide.
If you are the publisher and think this repository should not be public, just write me an email at hugomatilla [at] gmail [dot] com and I will make it private.
Contributions: Issues, comments and pull requests are super welcome 😃
- 1.Table of Contents
- 2.Grammar
- 3.Objects
- 4.Functions
- 5. Inheritance
- 6 Arrays
- 8. Methods
- Array
- Function
- Number
- Object
- RegExp
- String
string.charAt(pos)
string.charCodeAt(pos)
string.concat(string…)
string.indexOf(searchString, position)
string.lastIndexOf(searchString, position)
string.localeCompare(that)
string.match(regexp)
string.replace(searchValue,replaceValue)
string.search(regexp)
string.slice(start, end)
string.split(separator, limit)
string.substring(start, end)
string.toLocaleLowerCase( )
string.toLocaleUpperCase( )
string.toLowerCase( )
string.toUpperCase( )
String.fromCharCode(char…)
- Awful Parts
- Bad Parts
- JSLint
- Undefined Variables and Functions
- Members
- Options
- Semicolon
- Line Breaking
- Comma
- Required Blocks
- Forbidden Blocks
- Expression Statements
for in
Statementswitch
Statement- var Statement
- with Statement
=
==
and!=
- Labels
- Confusing Pluses and Minuses
- ++ and --
- Bitwise Operators
eval
Is Evilvoid
- Regular Expressions
- Constructors and new
- Not Looked For
- HTML
- JSON
- Report
- JSON
Names are used for statements, variables, parameters, property names, operators, and labels.
abstract | else | instanceof | super |
boolean | enum | int | switch |
break | export | interface | synchronized |
byte | extends | let | this |
case | FALSE | long | throw |
catch | final | native | throws |
char | finally | new | transient |
class | float | null | TRUE |
const | for | package | try |
continue | function | private | typeof |
debugger | goto | protected | var |
default | if | public | void |
delete | implements | return | volatile |
do | import | short | while |
double | in | static | with |
alert | frames | outerHeight |
all | frameRate | outerWidth |
anchor | function | packages |
anchors | getClass | pageXOffset |
area | hasOwnProperty | pageYOffset |
Array | hidden | parent |
assign | history | parseFloat |
blur | image | parseInt |
button | images | password |
checkbox | Infinity | pkcs11 |
clearInterval | isFinite | plugin |
clearTimeout | isNaN | prompt |
clientInformation | isPrototypeOf | propertyIsEnum |
close | java | prototype |
closed | JavaArray | radio |
confirm | JavaClass | reset |
constructor | JavaObject | screenX |
crypto | JavaPackage | screenY |
Date | innerHeight | scroll |
decodeURI | innerWidth | secure |
decodeURIComponent | layer | select |
defaultStatus | layers | self |
document | length | setInterval |
element | link | setTimeout |
elements | location | status |
embed | Math | String |
embeds | mimeTypes | submit |
encodeURI | name | taint |
encodeURIComponent | NaN | text |
escape | navigate | textarea |
eval | navigator | top |
event | Number | toString |
fileUpload | Object | undefined |
focus | offscreenBuffering | unescape |
form | open | untaint |
forms | opener | valueOf |
frame | option | window |
onbeforeunload | ondragdrop | onkeyup | onmouseover |
onblur | onerror | onload | onmouseup |
ondragdrop | onfocus | onmousedown | onreset |
onclick | onkeydown | onmousemove | onsubmit |
oncontextmenu | onkeypress | onmouseout | onunload |
Only one number type. 64-bit floating point. (Java double)
NaN
is a number of an operation that cannot produce a normal result. Use isNaN(number)
to detect it.
Infinity
represents all values greater than 1.79769313486231570e+308
.
Strings can be wrapped in single quotes or double quotes.
The \
(backslash) is the escape character.
Characters in JavaScript are 16 bits wide.
Escape sequences allow for inserting characters into strings that are not normally permitted
Strings have a length
property
Strings are immutable.
A compilation unit contains a set of executable statements.
Blocks
in JavaScript do not create a new scope, so variables should be defined at the top of the function, not in blocks.
false
null
undefined
- The empty string ''
- The number 0
- The number
NaN
All other values are truthy, including true, the string 'false', and all objects.
The simplest expressions are:
- a literal value (such as a string or number)
- a variable
- a built-in value (true, false, null, undefined, NaN, or Infinity)
- an invocation expression preceded by new
- a refinement expression preceded by delete
- an expression wrapped in parentheses
- an expression preceded by a prefix operator
- an expression followed by:
- An infix operator and another expression
- The ? ternary operator followed by another expression, then by :, and then byyet another expression
- An invocation
- A refinement
| . [] ( ) | Refinement and invocation | | delete new typeof + - ! | Unary operators | | * / % | Multiplication, division, modulo | | + - | Addition/concatenation, subtraction | | >= <= > < | Inequality | | === !== | Equality | | && | Logical and | | || | Logical or | | ?: | Ternary |
The values produced by typeof are 'number', 'string', 'boolean', 'undefined','function', and 'object'. If the operand is an array or null, then the result is 'object', which is wrong.
The + operator adds or concatenates. If you want it to add, make sure both operands are numbers.
The / operator can produce a noninteger result even if both operands are integers.
Invocation causes the execution of a function value.
Specify a property or element of an object or array
A function literal defines a function value.
It can have an optional name that it can use to call itself recursively.
Numbers, strings, and booleans are not objects the rest are.
Numbers, strings, and booleans are object-like in that they have methods, but they are immutable.
Objects in JavaScript are mutable keyed collections.
An object is a container of properties, where a property has a name and a value.
- A property name can be any string, including the empty string.
- A property value can be any JavaScript value except for
undefined
.
Objects in JavaScript are class-free.
JavaScript includes a prototype linkage feature that allows one object to inherit the properties of another.
An object literal is a pair of curly braces surrounding zero or more name/value pairs.
var empty_object = {};
var stooge = {
"first-name": "Jerome",
"last-name": "Howard"
};
Values can be retrieved from an object by wrapping a string expression in a [ ] suffix.
Dot .
notation can be use if the string expression is a constant, legal and not a reserved word.
undefined
value is produced if an attempt is made to retrieve a nonexistent member.
stooge.middle-name //undefined
||
can be used to fill default values
var middle = stooge["middle-name"] || "(none)";
&&
to avoid TypeError exception when retrieving values from undefined
flight.equipment // undefined
flight.equipment.model // throw "TypeError"
flight.equipment && flight.equipment.model // undefined
Updated by assignment. If exists it changes if not it is added.
stooge['first-name'] = 'Jerome';
Objects are passed around by reference. They are never copied
Every object is linked to a prototype object from which it can inherit properties.
All Objects are linked to Object.prototype
, an object that comes standard with JavaScript.
When you make a new object, you can select the object that should be its prototype.
Use typeof
to determine what properties an object has.
hasOwnProperty
method, which returns true if the object has a particular property. It does not look at the prototype chain
flight.hasOwnProperty('number') // true
flight.hasOwnProperty('constructor') // false
The for in statement can loop over all of the property names in an object, including functions and prototype properties that you might not be interested.
Filter them using typeof
. The order will not be guaranteed
var name;
for (name in another_stooge) {
if (typeof another_stooge[name] !== 'function') {
document.writeln(name + ': ' + another_stooge[name]);
}
}
delete
removes a property from an object.
JavaScript makes it easy to define global variables but they weaken the resiliency of programs and should be avoided.
Create a single global variable for your application:
var MYAPP = {};
MYAPP.stooge = {
"first-name": "Joe",
"last-name": "Howard"
};
MYAPP.flight = {
airline: "Oceanic",
number: 815,
...
};
By reducing your global footprint to a single name, you significantly reduce the chance of bad interactions with other applications, widgets, or libraries.
- Functions are objects.
- Objects are collections of name/value pairs.
- Objects have a hidden link to a prototype object.
- Objects produced from object literals are linked to Object.prototype.
- Function objects are linked to Function.prototype (which is linked to Object.prototype)
- Every function is created with two additional hidden properties: *the function’s context *the code that implements the function’s behavior.
- Every function object is created with a
prototype
property. Its value is an object with aconstructor
property whose value is the function. This is distinct from the hidden link to Function.prototype. - Functions (because they are objects) can be:
- stored in variables, objects, and arrays.
- passed as arguments to functions
- returned from functions.
- have methods.
The special thing about functions is that they can be invoked.
Function objects are created with function literals:
var add = function (a, b) {
return a + b;
};
A function literal has four parts:
-
- reserved word
function
.
- reserved word
-
- The optional function’s name. If no name, it is called
anonymous function
.
- The optional function’s name. If no name, it is called
-
- Set of parameters wrapped in parentheses.
-
- A set of statements wrapped in curly braces. These statements are the body of the function. They are executed when the function is invoked.
Closure A link to the outer function context.
Invoking a function suspends the execution of the current function, passing control and parameters to the new function. In addition to the declared parameters, every
function receives two additional parameters: this
and arguments
.
this
:is determined by the invocation pattern.
There are four patterns of invocation in JavaScript:
- the method invocation pattern,
- the function invocation pattern,
- the constructor invocation pattern,
- the apply invocation pattern.
The patterns differ in how the bonus parameter this is initialized.
When a function is stored as a property of an object, we call it a method.
When a method is invoked, this is bound to that object. If an invocation expression contains a refinement (that is, a . dot expression or [subscript] expression), it is invoked as a method:
myObject.increment(2);
The binding of this
to the object happens at invocation time.
Methods that get their object context from this are called public methods.
When a function is not the property of an object, then it is invoked as a function:
var sum = add(3, 4); // sum is 7
When a function is invoked with this pattern, this
is bound to the global object. It should be to the outer function.
Defining a variable and assigns it the value of this
will make the trick.
By convention, the name of that variable is that:
// Augment myObject with a double method.
myObject.double = function ( ) {
var that = this; // Workaround.
var helper = function ( ) {
that.value = add(that.value, that.value);
};
helper( ); // Invoke helper as a function.
};
If a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function’s prototype member, and this will be bound to that new object.
Use of this style of constructor functions is not recommended.
var Quo = function (string) {
this.status = string;
}
Quo.prototype.get_status = function ( ) {
return this.status;
}
var myQuo = new Quo("confused");
document.writeln(myQuo.get_status( )); // confused
Functions can have methods.
The apply method lets us construct an array of arguments to use to invoke a function.
It also lets us choose the value of this.
The apply method takes two parameters.
The first is the value that should be bound to this.
The second is an array of parameters.
var array = [3, 4];
var sum = add.apply(null, array); // sum is 7
var statusObject = {
status: 'A-OK'
};
// statusObject does not inherit from Quo.prototype,
// but we can invoke the get_status method on
// statusObject even though statusObject does not have
// a get_status method.
var status = Quo.prototype.get_status.apply(statusObject);
// status is 'A-OK'
A bonus parameter that is available to functions when they are invoked is the arguments array. It gives the function access to all of the arguments that were supplied with the invocation, including excess arguments that were not assigned to parameters.
var sum = function ( ) {
var i, sum = 0;
for (i = 0; i < arguments.length; i += 1) {
sum += arguments[i];
}
return sum;
};
document.writeln(sum(4, 8, 15, 16, 23, 42)); // 108
arguments
is not really an array. It is an array-like object.arguments
has a length property, but it lacks all of the array methods.
When a function is invoked, it begins execution with the first statement, and ends when it hits the } that closes the function body.
That causes the function to return control to the part of the program that invoked the function.
The return statement can be used to cause the function to return early. When return is executed, the function returns immediately without executing the remaining statements.
A function always returns a value. If the return value is not specified, then undefined is returned.
If the function was invoked with the new prefix and the return value is not an object, then this (the new object) is returned instead
if (typeof a !== 'number' || typeof b !== 'number') {
throw {
name: 'TypeError',
message: 'add needs numbers'
};
}
return a + b;
}
The throw statement interrupts execution of the function.
It should be given an exception object containing a name and message. The exception object will be delivered to the catch clause of a try statement:
var try_it = function ( ) {
try {
add("seven");
} catch (e) {
document.writeln(e.name + ': ' + e.message);
}
}
try_it( );
A try statement has a single catch block that will catch all exceptions.
The exception handler will have to inspect the name to determine the type of the exception.
JavaScript allows the basic types of the language to be augmented.
For example, by augmenting Function.prototype
, we can make a method available to all functions:
Function.prototype.method = function (name, func) {
this.prototype[name] = func;
return this;
};
Number.method('integer', function ( ) {
return Math[this < 0 ? 'ceiling' : 'floor'](this);
});
document.writeln((-10 / 3).integer( )); // -3
The prototypes of the basic types are public structures, so care must be taken when mixing libraries. One defensive technique is to add a method only if the method is known to be missing:
Function.prototype.method = function (name, func) {
if (!this.prototype[name]) {
this.prototype[name] = func;
}
};
A recursive function is a function that calls itself, either directly or indirectly.
Recursion is a powerful programming technique in which a problem is divided into a set of similar subproblems, each solved with a trivial solution.
Scope in a programming language controls the visibility and lifetimes of variables and parameters.
var foo = function ( ) {
var a = 3, b = 5;
var bar = function ( ) {
var b = 7, c = 11;
// At this point, a is 3, b is 7, and c is 11
a += b + c;
// At this point, a is 21, b is 7, and c is 11
};
// At this point, a is 3, b is 5, and c is not defined
bar( );
// At this point, a is 21, b is 5
};
JavaScript does not have block scope.
JavaScript does have function scope. The parameters and variables defined in a function are not visible outside of the function, and that a variable defined anywhere within a function is visible everywhere within the function
The good news about scope is that inner functions get access to the parameters and variables of the functions they are defined within (with the exception of this and arguments). This is a very good thing.
var quo = function (status) {
return {
get_status: function ( ) {
return status;
}
};
};
// Make an instance of quo.
var myQuo = quo("amazed");
console.log(myQuo.get_status( ));
When we call quo, it returns a new object containing a get_status
method.
A reference to that object is stored in myQuo.
The get_status
method still has privileged access to quo’s status
property even though quo has already returned.
get_status
does not have access to a copy of the parameter; it has access to the parameter itself.
This is possible because the function has access to the context in which it was created. This is called closure.
Functions can make it easier to deal with discontinuous events.
request = prepare_the_request( );
send_request_asynchronously(request, function (response) {
display(response);
});
We pass a function parameter to the send_request_asynchronously
function that will be called when the response is available.
A module is a function or object that presents an interface but that hides its state and implementation.
By using functions to produce modules, we can almost completely eliminate our use of global variables, thereby mitigating one of JavaScript’s worst features.
The module pattern takes advantage of function scope and closure to create relationships that are binding and private. In this example, only the deentityify method has access to the entity data structure.
The general pattern of a 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.
Use of the module pattern can eliminate the use of global variables. It promotes information hiding and other good designs practices.
var serial_maker = function ( ) {
var prefix = '';
var seq = 0;
return {
set_prefix: function (p) {
prefix = String(p);
},
set_seq: function (s) {
seq = s;
},
gensym: function ( ) {
var result = prefix + seq;
seq += 1;
return result;
}
};
};
var seqer = serial_maker( );
seqer.set_prefix = ('Q';)
seqer.set_seq = (1000);
var unique = seqer.gensym( ); // unique is "Q1000"
The methods do not make use of this or that. As a result, there is no way to compromise the seqer
.
It isn’t possible to get or change the prefix
or seq
except as permitted by the methods.
The seqer object is mutable, so the methods could be replaced, but that still does not give access to its secrets.
seqer
is simply a collection of functions, and those functions are capabilities that grant specific powers to use or modify the secret state.
If we passed seqer.gensym
to a third party’s function, that function would be able to generate unique strings, but would be unable to change the prefix or seq.
Some methods do not have a return value.
If we have those methods return this instead of undefined, we can enable cascades.
getElement('myBoxDiv').
move(350, 150).
width(100).
height(100).
color('red').
border('10px outset')
Functions are values, and we can manipulate function values in interesting ways.
Currying allows us to produce a new function by combining a function and an argument:
var add1 = add.curry(1);
document.writeln(add1(6)); //7
JavaScript does not have a curry method, but we can fix that by augmenting Function.prototype:
Function.method('curry', function ( ) {
var slice = Array.prototype.slice,
args = slice.apply(arguments),
that = this;
return function ( ) {
return that.apply(null, args.concat(slice.apply(arguments)));
};
});
Functions can use objects to remember the results of previous operations, making it possible to avoid unnecessary work.
This optimization is called memoization.
We will keep our memoized results in a memo array that we can hide in a closure.
When our function is called, it first looks to see if it already knows the result.
If it does, it can immediately return it:
var fibonacci = function ( ) {
var memo = [0, 1];
var fib = function (n) {
var result = memo[n];
if (typeof result !== 'number') {
result = fib(n - 1) + fib(n - 2);
memo[n] = result;
}
return result;
};
return fib;
}( );
A generalized version:
var memoizer = function (memo, fundamental) {
var shell = function (n) {
var result = memo[n];
if (typeof result !== 'number') {
result = fundamental(shell, n);
memo[n] = result;
}
return result;
};
return shell;
};
var fibonacci = memoizer([0, 1], function (shell, n) {
return shell(n - 1) + shell(n - 2);
});
In classical languages, objects are instances of classes, and a class can inherit from another class. JavaScript is a prototypal language, which means that objects inherit directly from other objects.
A much better alternative is to not use new at all.
The pseudoclassical form can provide comfort to programmers who are unfamiliar
The classically inspired notation can induce programmers to compose hierarchies that are unnecessarily deep and complicated.
Much of the complexity of class hierarchies is motivated by the constraints of static type checking. JavaScript is completely free of those constraints.
Use makers
when having a lot of arguments in the constructor of an object.
So, instead of:
var myObject = maker(f, l, m, c, s);
we can write:
var myObject = maker({
first: f,
last: l,
state: s,
city: c
});
We could also use a JSON with all the parameters as the argument.
Contrary to purely prototypal pattern, where we dispense with classes, in JavaScript we focus on the objects.
A new object can inherit the properties of an old object.
var myMammal = {
name : 'Herb the Mammal',
get_name : function ( ) {
return this.name;
},
says : function ( ) {
return this.saying || '';
}
};
Using create
from Chapter 3
var myCat = Object.create(myMammal);
myCat.name = 'Henrietta';
myCat.saying = 'meow';
myCat.purr = function (n) {
var i, s = '';
for (i = 0; i < n; i += 1) {
if (s) {
s += '-';
}
s += 'r';
}
return s;
};
myCat.get_name = function ( ) {
return this.says( ) + ' ' + this.name + ' ' + this.says( );
};
This is differential inheritance. By customizing a new object, we specify the differences from the object on which it is based.
One weakness of the inheritance patterns we have seen so far is that we get no privacy.
We make a function that will produce objects. It contains four steps:
- It creates a new object. There are lots of ways to make an object.
- It optionally defines private instance variables and methods. These are just ordinary vars of the function.
- It augments that new object with methods. Those methods will have privileged access to the parameters and the vars defined in the second step.
- It returns that new object.
var constructor = function (spec, my) {
var that, other private instance variables;
my = my || {};
// Add shared variables and functions to my
that = a new object;
//Add privileged methods to that
return that;
};
- The
spec
object contains all of the information that the constructor needs to make an instance. - The
my
object is a container of secrets that are shared by the constructors in the inheritance chain. - Declare the private instance variables and private methods for the object. This is done by simply declaring variables.
- Add the shared secrets to the
my
object. - Make a new object and assign it to
that
. - Augment that, adding the privileged methods that make up the object’s interface.
var methodical = function ( ) {
...
};
that.methodical = methodical;
- Return
that
The name and saying properties are now completely private. They are accessible only via the privileged get_name and says methods:
var mammal = function (spec) {
var that = {};
that.get_name = function ( ) {
return spec.name;
};
that.says = function ( ) {
return spec.saying || '';
};
return that;
};
var myMammal = mammal({name: 'Herb'});
var cat = function (spec) {
spec.saying = spec.saying || 'meow';
var that = mammal(spec);
that.purr = function (n) {
return 'r'.repeat(n);
};
that.get_name = function ( ) {
return that.says( ) + ' ' + spec.name + ' ' + that.says( );
};
return that;
};
var myCat = cat({name: 'Henrietta'});
The functional pattern also gives us a way to deal with super methods.
Make a superior method that takes a method name and returns a function that invokes that method.
Object.method('superior', function (name) {
var that = this,
method = that[name];
return function ( ) {
return method.apply(that, arguments);
};
});
var coolcat = function (spec) {
var that = cat(spec),
super_get_name = that.superior('get_name');
that.get_name = function (n) {
return 'like ' + super_get_name( ) + ' baby';
};
return that;
};
var myCoolCat = coolcat({name: 'Bix'});
var name = myCoolCat.get_name( );
// 'like meow Bix meow baby'
The functional pattern has a great deal of flexibility.
Gives us better encapsulation and information hiding and access to super methods.
Array literals provide a very convenient notation for creating new array values.
An array literal is a pair of square brackets surrounding zero or more values separated by commas.
Elements of an array are NOT required to be of the same type.
var empty = [];
var numbers = [
'zero', 'one', 'two', 'three', 'four',
'five', 'six', 'seven', 'eight', 'nine'
];
empty[1] // undefined
numbers[1] // 'one'
empty.length // 0
numbers.length // 10
var misc = [
'string', 98.6, true, false, null, undefined,
['nested', 'array'], {object: true}, NaN];
Every array has a length property.
JavaScript’s array length is not an upper bound.
There is no array bounds error.
The length property is the largest integer property name in the array plus one.
This is not necessarily the number of properties in the array:
var myArray = [];
myArray.length // 0
myArray[1000000] = true;
myArray.length // 1000001
// myArray contains one property.
The length can be set explicitly.
Making the length larger does not allocate more space for the array.
Making the length smaller will delete elements.
numbers.length = 3;
// numbers is ['zero', 'one', 'two']
A new element can be appended to the end of an array by assigning to the array’s current length:
numbers[numbers.length] = 'shi';
// numbers is ['zero', 'one', 'two', 'shi']
Use push for that
numbers.push('go');
// numbers is ['zero', 'one', 'two', 'shi', 'go']
Since JavaScript’s arrays are really objects, the delete operator can be used to remove elements from an array:
delete numbers[2];
// numbers is ['zero', 'one', undefined, 'shi', 'go']
Unfortunately, that leaves a hole in the array. Arrays are objects, indexes
([1], [3]) are the names
of the object.
array = {'0':'Peter', '1':'John'}
Names of the objects do not change after delete
Use splice
for that.
numbers.splice(2, 1);
// numbers is ['zero', 'one', 'shi', 'go']
The second argument is the number of elements to delete.
Any additional arguments get inserted into the array at that point.
Since JavaScript’s arrays are really objects, the for in
statement can be used to iterate over all of the properties of an array.
Unfortunately, for in makes no guarantee about the order of the properties,
Use for
instead
for (var i = 0; i < myArray.length; i += 1) {
document.writeln(myArray[i]);
}
When the property names are small sequential integers, you should use an array. Otherwise, use an object.
NOTE: typeof
operator reports that the type of an array is 'object.
Use:
var is_array = function (value) {
return Object.prototype.toString.apply(value) === '[object Array]';
};
##Methods JavaScript provides a set of methods for acting on arrays.
Array.prototype can be augmented as well.
Add the reduce
method to arrays:
Array.method('reduce', function (f, value) {
var i;
for (i = 0; i < this.length; i += 1) {
value = f(this[i], value);
}
return value;
});
var data = [4, 8, 10];
var add = function (a, b) {
return a + b;
};
var sum = data.reduce(add, 0); // sum is 22
We can also add methods directly to an individual array:
data.total = function ( ) {
return this.reduce(add, 0);
};
total = data.total( ); // total is 22
Since the string 'total' is not an integer, adding a total property to an array does not change its length
.
Add array initializers
Array.dim = function (dimension, initial) {
var a = [], i;
for (i = 0; i < dimension; i += 1) {
a[i] = initial;
}
return a;
};
// Make an array containing 10 zeros.
var myArray = Array.dim(10, 0);
Add Matrix
Array.matrix = function (m, n, initial) {
var a, i, j, mat = [];
for (i = 0; i < m; i += 1) {
a = [];
for (j = 0; j < n; j += 1) {
a[j] = initial;
}
mat[i] = a;
}
return mat;
};
// Make a 4 * 4 matrix filled with zeros.
var myMatrix = Array.matrix(4, 4, 0);
#8. Methods
The concat method produces a NEW array containing a shallow copy of this array with the items appended to it.
var a = ['a', 'b', 'c'];
var b = ['x', 'y', 'z'];
var c = a.concat(b, true);
// c is ['a', 'b', 'c', 'x', 'y', 'z', true]
The join method makes a string from an array.
var a = ['a', 'b', 'c'];
a.push('d');
var c = a.join(''); // c is 'abcd';
The pop and push methods make an array work like a stack.
var a = ['a', 'b', 'c'];
var c = a.pop( ); // a is ['a', 'b'] & c is 'c'
The push method appends items to the end of an array. Unlike the concat method, it modifies the array and appends array items whole. It returns the new length:
var a = ['a', 'b', 'c'];
var b = ['x', 'y', 'z'];
var c = a.push(b, true);
// a is ['a', 'b', 'c', ['x', 'y', 'z'], true]
// c is 5;
The reverse method modifies the array by reversing the order of the elements.
It returns the array
var a = ['a', 'b', 'c'];
var b = a.reverse( );
// both a and b are ['c', 'b', 'a']
The shift method removes the first element from an array and returns it. Usually Slower than pop
var a = ['a', 'b', 'c'];
var c = a.shift( ); // a is ['b', 'c'] & c is 'a'
The slice method makes a shallow copy of a portion of an array.
var a = ['a', 'b', 'c'];
var b = a.slice(0, 1); // b is ['a']
var c = a.slice(1); // c is ['b', 'c']
var d = a.slice(1, 2); // d is ['b']
The sort method sorts the contents of an array in place.
It sorts arrays of numbers incorrectly:
var n = [4, 8, 15, 16, 23, 42];
n.sort( );
// n is [15, 16, 23, 4, 42, 8]
You may replace the comparison function with your own.
Your comparison function should take two parameters and return 0 if the two parameters are equal, a negative number if the first parameter should come first, and a positive number if the second parameter should come first.
n.sort(function (a, b) {
return a - b;
});
// n is [4, 8, 15, 16, 23, 42];
The splice method removes elements from an array, replacing them with new items.
var a = ['a', 'b', 'c'];
var r = a.splice(1, 1, 'ache', 'bug');
// a is ['a', 'ache', 'bug', 'c']
// r is ['b']
The unshift method is like the push method except that it shoves the items onto the front of this array instead of at the end.
It returns the array’s new length:
var a = ['a', 'b', 'c'];
var r = a.unshift('?', '@');
// a is ['?', '@', 'a', 'b', 'c']
// r is 5
The apply method invokes a function, passing in the object that will be bound to this and an optional array of arguments.
The apply method is used in the The Apply Invocation Pattern
The toExponential
method converts this number to a string in the exponential form.
The optional fractionDigits parameter controls the number of decimal places.
It should be between 0 and 20:
document.writeln(Math.PI.toExponential(0)); // 3e+0
document.writeln(Math.PI.toExponential(2)); // 3.14e+0
document.writeln(Math.PI.toExponential(7)); // 3.1415927e+0
document.writeln(Math.PI.toExponential(16)); // 3.1415926535897930e+0
document.writeln(Math.PI.toExponential( )); // 3.141592653589793e+0
The toFixed
method converts this number to a string in the decimal form.
The optional fractionDigits parameter controls the number of decimal places.
It should be between 0 and 20. The default is 0:
document.writeln(Math.PI.toFixed(0)); // 3
document.writeln(Math.PI.toFixed(2)); // 3.14
document.writeln(Math.PI.toFixed(7)); // 3.1415927
document.writeln(Math.PI.toFixed(16)); // 3.1415926535897930
document.writeln(Math.PI.toFixed( )); // 3
The toPrecision
method converts this number to a string in the decimal form.
The optional precision parameter controls the number of digits of precision.
It should be between 1 and 21:
document.writeln(Math.PI.toPrecision(2)); // 3.1
document.writeln(Math.PI.toPrecision(7)); // 3.141593
document.writeln(Math.PI.toPrecision(16)); // 3.141592653589793
document.writeln(Math.PI.toPrecision( )); // 3.141592653589793
The toString
method converts this number to a string.
The optional radix parameter controls radix, or base.
It should be between 2 and 36.
The default radix is base 10.
The radix parameter is most commonly used with integers, but it can be used on any number.
document.writeln(Math.PI.toString(2)); // 11.001001000011111101101010100010001000010110100011
document.writeln(Math.PI.toString(8)); // 3.1103755242102643
document.writeln(Math.PI.toString(16)); // 3.243f6a8885a3
document.writeln(Math.PI.toString( )); // 3.141592653589793
The hasOwnProperty
method returns true if the object contains a property having the name.
The prototype chain is not examined.
This method is useless if the name is hasOwnProperty
var a = {member: true};
var b = Object.create(a); // from Chapter 3
var t = a.hasOwnProperty('member'); // t is true
var u = b.hasOwnProperty('member'); // u is false
var v = b.member; // v is true
The exec method is the most powerful (and slowest) of the methods that use regular expressions.
If it successfully matches the regexp and the string, it returns an array.
The 0 element of the array will contain the substring that matched the regexp.
The 1 element is the text captured by group 1, the 2 element is the text captured by group 2, and so on.
If the match fails, it returns null.
The test method is the simplest (and fastest) of the methods that use regular expressions.
If the regexp matches the string, it returns true; otherwise, it returns false.
Do not use the g
flag with this method:
var b = /&.+;/.test('frank & beans');
// b is true
The charAt
method returns the character at position pos in this string.
If pos is less than zero or greater than or equal to string.length
, it returns the empty string.
var name = 'Curly';
var initial = name.charAt(0); // initial is 'C'
The charCodeAt
method is the same as charAt
except that instead of returning a string, it returns an integer representation of the code point value of the character at position pos
in
that string.
If pos
is less than zero or greater than or equal to string.length
, it returns NaN
var name = 'Curly';
var initial = name.charCodeAt(0); // initial is 67
The concat
method makes a new string by concatenating other strings together.
It is rarely used because the + operator is more convenient:
var s = 'C'.concat('a', 't'); // s is 'Cat'
The indexOf
method searches for a searchString within a string.
If it is found, it returns the position of the first matched character;otherwise, it returns –1.
The optional position parameter causes the search to begin at some specified position in the string
var text = 'Mississippi';
var p = text.indexOf('ss'); // p is 2
p = text.indexOf('ss', 3); // p is 5
p = text.indexOf('ss', 6); // p is -1
The lastIndexOf
method is like the indexOf
method, except that it searches from the end of the string instead of the front:
var text = 'Mississippi';
var p = text.lastIndexOf('ss'); // p is 5
p = text.lastIndexOf('ss', 3); // p is 2
p = text.lastIndexOf('ss', 6); // p is 5
The localCompare
method compares two strings.
The rules for how the strings are compared are not specified.
If this string is less than that string, the result is negative.
If they are equal, the result is zero.
This is similar to the convention for the array.sort
comparison function:
var m = ['AAA', 'A', 'aa', 'a', 'Aa', 'aaa'];
m.sort(function (a, b) {
return a.localeCompare(b);
});
// m (in some locale) is
// ['a', 'A', 'aa', 'Aa', 'aaa', 'AAA']
The match method matches a string and a regular expression.
How it does this depends on the g
flag.
If there is no g flag, then the result of calling string.match(regexp)
is the same as calling regexp.exec(string)
.
However, if the regexp has the g
flag, then it produces an array of all the matches but excludes the capturing groups.
var text = '<html><body bgcolor=linen><p>' +
'This is <b>bold<\/b>!<\/p><\/body><\/html>';
var tags = /[^<>]+|<(\/?)([A-Za-z]+)([^<>]*)>/g;
var a, i;
a = text.match(tags);
for (i = 0; i < a.length; i += 1) {
document.writeln(('// [' + i + '] ' + a[i]).entityify( ));
}
// The result is
// [0] <html>
// [1] <body bgcolor=linen>
// [2] <p>
// [3] This is
// [4] <b>
// [5] bold
// [6] </b>
// [7] !
// [8] </p>
// [9] </body>
// [10] </html>
The replace
method does a search and replace operation on this string, producing a new string.
The searchValue argument can be a string or a regular expression object.
If it is a string, only the first occurrence of the searchValue is replaced
var result = "mother_in_law".replace('_', '-');
will produce "mother-in_law", which might be a disappointment.
If searchValue is a regular expression and if it has the g
flag, then it will replace all occurrences.
If it does not have the g
flag, then it will replace only the first ccurrence.
The replaceValue can be a string or a function.
Dollar sequence | Replacement |
---|---|
$$ | $ |
$& | The matched text |
$ number | Capture group text |
$` | The text preceding the match |
$' | The text following the match |
If the replaceValue is a function, it will be called for each match, and the string returned by the function will be used as the replacement text.
The first parameter passed to the function is the matched text.
The search
method is like the indexOf method, except that it takes a regular expression object instead of a string.
The g flag is ignored.
var text = 'and in it he says "Any damn fool could';
var pos = text.search(/["']/); // pos is 18
The slice
method makes a new string by copying a portion of another string.
If the start parameter is negative, it adds string.length
to it.
The end parameter is optional, and its default value is string.length
.
If the end parameter is negative, then string.length is added to it.
The end parameter is one greater than the position of the last character.
var text = 'and in it he says "Any damn fool could';
var a = text.slice(18);
// a is '"Any damn fool could'
var b = text.slice(0, 3);
// b is 'and'
var c = text.slice(-5);
// c is 'could'
var d = text.slice(19, 32);
// d is 'Any damn fool'
The split
method creates an array of strings by splitting this string into pieces.
The optional limit parameter can limit the number of pieces that will be split.
The separator parameter can be a string or a regular expression.
If the separator is the empty string, an array of single characters is produced:
var digits = '0123456789';
var a = digits.split('', 5);
// a is ['0', '1', '2', '3', '456789']
Otherwise, the string is searched for all occurrences of the separator.
Each unit of text between the separators is copied into the array.
The g
flag is ignored:
var ip = '192.168.1.0';
var b = ip.split('.');
// b is ['192', '168', '1', '0']
var c = '|a|b|c|'.split('|');
// c is ['', 'a', 'b', 'c', '']
The substring
method is the same as the slice method except that it doesn’t handle the
adjustment for negative parameters.
There is no reason to use the substring method. Use slice instead.
The toLocaleLowerCase
method produces a new string that is made by converting this
string to lowercase using the rules for the locale.
This is primarily for the benefit of Turkish because in that language ‘I’ converts to ı, not ‘i’.
The toLocaleUpperCase
method produces a new string that is made by converting this
string to uppercase using the rules for the locale.
This is primarily for the benefit of Turkish, because in that language ‘i’ converts to ‘ ’, not ‘I’.
The toLowerCase
method produces a new string that is made by converting this string to
lowercase.
The toUpperCase
method produces a new string that is made by converting this string to
uppercase.
The String.fromCharCode
function produces a string from a series of numbers.
var a = String.fromCharCode(67, 97, 116);
// a is 'Cat'
A global variable is a variable that is visible in every scope.
Because a global variable can be changed by any part of the program at any time, they can significantly complicate the behavior of the program.
There are three ways to define global variables.
- Place a var statement outside of any function:
var foo = value;
- Add a property directly to the global object. ie:
window.foo = value;
- Use a variable without declaring it.
foo = value;
JavaScript’s policy of making forgotten variables global creates bugs that can be very difficult to find.
JavaScript uses the block syntax, but does not provide block scope:
A variable declared in a block is visible everywhere in the function containing the block.
Best practice is to declare all variables at the top of each function.
JavaScript has a mechanism that tries to correct faulty programs by automatically inserting semicolons.
Do not depend on this. It can mask more serious errors.
return
{
status: true
};
// returns undefined
return {
status: true
};
//returns an object
The following words are reserved in JavaScript:
abstract boolean break byte case catch char class const continue debugger default delete do double else enum export extends false final finally float for function goto if implements import in instanceof int interface long native new null package private protected public return short static super switch synchronized this throw throws transient true try typeof var volatile void while with
They cannot be used to name variables or parameters.
When reserved words are used as keys in object literals, they must be quoted.
They cannot be used with the dot notation, so it is sometimes necessary to use the bracket notation instead.
var method; // ok
var class; // illegal
object = {box: value}; // ok
object = {case: value}; // illegal
object = {'case': value}; // ok
object.box = value; // ok
object.case = value; // illegal
object['case'] = value; // ok
JavaScript’s characters are 16 bits. That is enough to cover the original 65,536 (which is now known as the Basic Multilingual Plane).
Each of the remaining million characters can be represented as a pair of characters.
Unicode considers the pair to be a single character.
JavaScript thinks the pair is two distinct characters.
typeof null
returns object
You can fix it with:
if (my_value && typeof my_value === 'object') {
// my_value is an object or an array!
}
Some implementations report that:
typeof /a/
is object
, and others say that it is function
.
parseInt
is a function that converts a string into an integer.
parseInt("16")
and parseInt("16 tons")
produce the same result.
If the first character of the string is 0, then the string is evaluated in base 8 instead of base 10.
parseInt("08")
and parseInt("09")
produce 0 as their result.
Fortunately, parseInt
can take a radix
parameter, so that parseInt("08",10)
produces 8.
Use always the radix
The + operator can add or concatenate.
Which one it does depends on the types of the parameters.
If either operand is an empty string, it produces the other operand converted to a string.
If both operands are numbers, it produces the sum.
Otherwise, it converts both operands to strings and concatenates them.
Binary floating-point numbers are inept at handling decimal fractions, so 0.1 + 0.2 is not equal to 0.3.
Use Integer aritmetic. ie: 1.05$ = 105/100 $
The value NaN is a special quantity defined by IEEE 754. It stands for not a number, even though:
typeof NaN === 'number' // true
The value can be produced by attempting to convert a string to a number when the string is not in the form of a number. For example:
+ '0' // 0
+ 'oops' // NaN
NaN
is not equal to itself.
NaN === NaN // false
NaN !== NaN // true
isNaN
function that can distinguish between numbers and NaN
:
isNaN(NaN) // true
isNaN(0) // false
isNaN('oops') // true
isNaN('0') // false
You may want to define your own isNumber function:
var isNumber = function isNumber(value) {
return typeof value === 'number' && isFinite(value);
}
Javascript arrays can be considerably worse than real arrays
The typeof operator does not distinguish between arrays and objects. You need
if (my_value && typeof my_value === 'object' && typeof my_value.length === 'number' && !(my_value.propertyIsEnumerable('length')) {
// my_value is truly an array!
}
In any case, the test can still fail if the propertyIsEnumerable method is overridden.
JavaScript has a surprisingly large set of falsy values
Value | Type |
---|---|
0 | Number |
NaN (not a number) | Number |
'' (empty string) | String |
false | Boolean |
null | Object |
undefined | Undefined |
Unfortunately, hasOwnProperty
is a method, not an operator, so in any object it could be replaced.
JavaScript’s objects are never truly empty because they can pick up members from the prototype chain.
And sometimes that matters.
Use always ===
and !==
instead.
'' == '0' // false
0 == '' // true
0 == '0' // true
false == 'false' // false
false == '0' // true
false == undefined // false
false == null // false
null == undefined // true
' \t\r\n ' == 0 // true
the with
statement was intended to provide a shorthand when
accessing the properties of an object.
Unfortunately, its results can sometimes be unpredictable, so it should be avoided.
The eval function passes a string to the JavaScript compiler and executes the result.
Should be avoided as setInterval
, setTimeout
and the Function constructor
The continue statement jumps to the top of the loop.
The switch statement was modeled after the FORTRAN IV computed go to statement.
Each case falls through into the next case unless you explicitly disrupt the flow
An if or while or do or for statement can take a block or a single statement.
if (ok)
t = true;
//can become:
if (ok)
t = true;
advance( );
//which looks like:
if (ok) {
t = true;
advance( );
}
//but which actually means:
if (ok) {
t = true;
}
advance( );
When ++
and --
are used , the code tended to be too
tight, too tricky, too cryptic.
Don’t use them
JavaScript has the same set of bitwise operators as Java:
& and
| or
^ xor
~ not
>> signed right shift
>>> unsigned right shift
<< left shift
Bitwise operators convert their number operands into integers, do their business, and then convert them back.
They are slow
The statement:
function foo( ) {}
means about the same thing as:
var foo = function foo( ) {};
function
statements are subject to hoisting. This means that regardless of where a function
is placed, it is moved to the top of the scope in which it is defined.
The first thing in a statement cannot be a function expression because the official grammar assumes that a statement that starts with the word function is a function statement.
The workaround is to wrap the function expression in parentheses:
(function ( ) {
var hidden_variable;
// This function can have some impact on
// the environment, but introduces no new
// global variables.
})();
JavaScript has a set of typed wrappers. For example:
new Boolean(false)
Don’t use new Boolean
or new Number
or new String
.
Also avoid new Object
and new Array
. Use {}
and []
instead
new
JavaScript’s new operator creates a new object that inherits from the operand’s prototype
member, and then calls the operand, binding the new object to this. This gives
the operand (which had better be a constructor function) a chance to customize the
new object before it is returned to the requestor.
If youforget to use the new operator, youinstead get an ordinary function call, and this is bound to the global object instead of to a new object. That means that your function will be clobbering global variables when it attempts to initialize the new members.
Not use new
at all.
void
is an operator that takes an operand and returns undefined
.
This is not useful, and it is very confusing.
Avoid void.
JSLint expects that all variables and functions will be declared before they are used or invoked. This allows it to detect implied global variables.
Since JavaScript is a loosely typed dynamic-object language, it is not possible to determine at compile time if property names are spelled correctly.
JSLint provides some assistance with this.
At the bottom of its report, JSLint displays a /*members*/
comment. It contains all of the names and string literals that were used with dot notation, subscript notation, and object literals to name the members of objects.
Option | Meaning |
---|---|
adsafe | true if ADsafe.org rules should be enforced |
bitwise | true if bitwise operators should not be allowed |
browser | true if the standard browser globals should be predefined |
cap | true if uppercase HTML should be allowed |
debug | true if debugger statements should be allowed |
eqeqeq | true if === should be required |
evil | true if eval should be allowed |
forin | true if unfiltered for in statements should be allowed |
fragment | true if HTML fragments should be allowed |
glovar | true if var should not be allowed to declare global variables |
laxbreak | true if statement breaks should not be checked |
nomen | true if names should be checked |
on | true if HTML event handlers should be allowed |
passfail | true if the scan should stop on first error |
plusplus | true if ++ and -- should not be allowed |
rhino | true if the Rhino environment globals should be predefined |
undef | true if undefined global variables are errors |
white | true if strict whitespace rules apply |
widget | true if the Yahoo! Widgets globals should be predefined |
JSLint expects that every statement be followed by ; except for for
, function
, if
, switch
, try
, and while
.
JSLint expects long statements to be broken only after one of these punctuation characters or operators:
, . ; : { } ( [ = < > ? ! + - * / % ~ ^ | & == != <= >= += -= *= /= %= ^=
JSLint expects to see the comma used as a separator, but not as an operator
JSLint expects that if and for statements will be made with blocks—that is, with statements enclosed in braces ({}).
JSLint expects blocks with function, if, switch, while, for, do, and try statements and nowhere else.
An expression statement is expected to be an assignment, a function/method call, or delete.
The body of every for in
statement should be wrapped in an if
statement that does filtering.
JSLint expects that the statement before the next case or default
is one of these: break
, return
, or throw
.
JSLint expects that:
- Avar will be declared only once, and that it will be declared before it is used.
- A function will be declared before it is used.
- Parameters will not also be declared as vars.
JSLint does not expect:
- The arguments array to be declared as a var.
- That a variable will be declared in a block. This is because JavaScript blocks do not have block scope.
Never use the with statement. Use a var instead.
JSLint does not expect to see a with statement.
JSLint does not expect to see an assignment statement in the condition part of an if or while statement. This is because it is more likely that:
...
}
Use
if ((a = b)) {
...
}
JSLint expects ===
or !==
operators.
JSLint expects labels only on statements that interact with break
: switch
, while
, do
, and for
.
JSLint expects that labels will be distinct from variables and parameters.
JSLint expects that a return
, break
, continue
, or throw
statement will be followed by a }
or case
or default
.
JSLint expects that + will not be followed by + or ++, and that - will not be followed by - or --.
The JSLint option plusplus prohibits the use of these operators.
JSLint does not expect bitwise operators.
JSLint does not expect evals.
JSLint does not expect to see void because it is confusing and not very useful.
JSLint looks for problems
that may cause portability problems. It also attempts to resolve visual ambiguities by recommending explicit escapement.
JSLint expects that the character preceding a regular expression literal is a (
or =
or :
or ,
character.
JSLint enforces the convention that constructor functions be given names with initial uppercase letters.
JSLint does not expect to see a function invocation with an initial uppercase name unless it has the new prefix.
JSLint does not expect to see the new prefix used with functions whose names do not start with initial uppercase.
JSLint does not expect to see the wrapper forms new Number
, new String
, or new Boolean
.
JSLint does not expect to see new Object
(use {}
instead).
JSLint does not expect to see new Array
(use []
instead).
JSLint does not chek if variables are assigned values before they are used.
JSLint does not do any kind of global analysis.
JSLint is able to handle HTML text.
JSLint can also check that JSON data structures are well formed.
If JSLint is able to complete its scan, it generates a function report. It lists the following for each function:
- The line number on which it starts.
- Its name. In the case of anonymous functions, JSLint will “guess” the name.
- The parameters.
- Closure: the variables and parameters that are declared in the function that are used by its inner functions.
- Variables: the variables declared in the function that are used only by the function.
- Unused: the variables that are declared in the function that are not used. This may be an indication of an error.
- Outer: variables used by this function that are declared in another function.
- Global: global variables that are used by this function.
- Label: statement labels that are used by this function.
The report will also include a list of all of the member names that were used.
JSON has six kinds of values: objects
, arrays
, strings
, numbers
, booleans
(true
and
false
), and the special value null
.
Whitespace (spaces, tabs, carriage returns, and newline characters) may be inserted before or after any value.
A JSON object is an unordered container of name/value pairs.
A name can be any string.
A value can be any JSON value, including arrays and objects.
JSON objects can be nested to any depth
The JSON array is an ordered sequence of values.
A value can be any JSON value, including arrays
and objects
.
A JSON string is wrapped in double quotes.
The \
character is used for escapement.
JSON allows the /
character to be escaped so that JSON can be embedded in HTML <script>
tags.
HTML does not allow the sequence </
except to start the </script>
tag.
JSON allows <\/
, which produces the same result but does not confuse HTML.
JSON numbers are like JavaScript numbers.
A leading zero is not allowed.
A number can be an integer, real, or scientific.
Use the JSON.parse