Javascript Notes

Just notes from various books/websites on JavaScript. Have tried to reference as thoroughly as possible.

Page Contents

References

  1. JavaScript Enlightenment, Cody Lindley, O'Reilly Media Inc, 2013
  2. The Principles Of Object-Oriented JavaScript, Nicholas C Zakas, William Pollock, 2014
  3. Javascript Closures, Richard Cornford, March 2004.
  4. ECMAScript 2015 Language Specification .

Testing

To test with IE, Microsoft offers virtual machines with different versions of IE installed. The downloads seem to be about 1GB in size so be patient!

Firefox can have multiple versions on the same machine.

Scope In JavaScript

Scope is the context in which code is executed, and there are three types in JavaScript.

  1. global scope,
  2. local scope (aka "function scope"),
  3. eval scope.

If you come from a C-ish background you may notice a pretty big ommission in the above list... there is no block scope!

JavaScript does not have block scope (pre ECMAScript 2015). Any variables declared in a block, i.e, { ... var xxx; ...} are local to the function in which they are declared or, worse, the global scope.

Note, however, that recently (at the time of writing) the ECMAScript 2015 has added something called the let statement to declare block scope local variables. May not be well supported for some time.

One thing that really got me was the use of var, or more precisely, what happens when you do not use var to declare local variables. If you do not declare a variable using var in a function it actually gets created in the global scope! One to watch out for.

Variables declared in a function that do NOT use var in the declaration are created in the global scope and not the function/local scope as you might expect.

To resolve a symbol, JavaScript goes down the scope chain: first look up symbol in the function/local scope, then in the parent scope, the grandparent scope, and so on, until the global scope is reached. The first symbol found is used. This is why closures work...

Every scope has a this object associated with it. In the global scope, this will most likely be the web browser window. In the function scope it will reference the object it is attached to (unless specifically modified - see later). The value of this is determined entirely at run time which is very different from languages like C++.

Every scope has a this reference associated with it. It is determined at run time.

For, example, if you define a function in your web browser's console so that it prints the contents of the this reference, you will see it pointing to the global scope object, which for the browser is the Window object:

function jehtech() { console.log(this); }
jehtech()
// Outputs:
// > Window {top: Window, location: Location, document: document, window: Window, ...}

If you do the same for a vanilla object you get the following:

jt = { objMethod : jehtech }
jt.objMethod()
// Outputs:
// > Object {}
// >> objMethod: function jehtech()
// >> __proto__: Object

So... you can see that when the same function is called in different contexts, it's this reference "points" to different objects: The value of this is based on the context in which the function is called and is determined at run time.

Closures In JavaScript

Closures work due to the scope chain that was described above. From parent function return a reference to the child function contained within it. When this child function (nested function) is invoked, it still has access to the parent function's scope because of the scope chain. See Richard Cornford's article [3] for further info.

Arrays

See array API on MDN.

  • new_array = array1.concat(array2, ..., arrayN)
    new_array is the concatenation of array1 with all the other arrays in the concat() argument list.
  • array.indexOf(x), array.lastIndexOf(x)
    Returns index of first/last instance of x in array or -1 if x is not in the array.
  • string = array.join()
    Concatenates all elements of array into a string
  • new_length = array.push(x1, x2, ..., xN)
    Pushes elements, in order, onto end of array.
  • item = array.pop()
    Removes element off end of array.
  • array.reverse()
    Reverses array elements in place.
  • sub_array = array.slice(start, end)
    Takes slice [start, end). Note that range does not include end index. Returns slice as new array, original not effected.
  • array.splice(start, deleteCount [,i1, i2... iN])
    Removes items from array and potentially also adds new.
  • item = array.shift()
    Like pop() but removes from start of array.
  • array.unshift(x)
    Like push() but puts at start of array.

Objects In JavaScript

I wanted to play with the HTML5 canvas to produce the little resitor calculator on the electronics page. To do this I decided to learn a little bit about JavaScript classes...

These notes are basically just notes made on the books referenced above and applied to creating some objects to draw boxes etc on a canvas.

How Objects Are Stored (vs. Primatives)

Primatives (things like ints, floats etc) are stored directly in the variable.
Everything else is stored as a reference type which is just a pointer to a memory location.

This means that primatives are deep copies. Modifying a copy of a primative will not affect the original primative:

var origVar = 999;
var copyVar = origVar;

copyVar = 123;
console.log(copyVar); // prints 123
console.log(origVar); // prints 999 - the original
                      // has NOT been modified!

Objects are not primatives. They are stored as references. This means that when a variable that points to an object is copied, all that is really copied is the reference to that object. Thus if the copied variable is modified, the original is modified because both variables refer to the same object:

var o1 = new Object();
var o2 = o1
o1.newAttr = "J" //< Note: can add property at any time
console.log(o1.newAttr); // o1.newAttr == "J"
console.log(o2.newAttr): // o2.newAttr == o1.newAttr == "J"

One thing to note in the above is the automatic way to add a property to an object. By assigning to a property that doesn't exist, the property is created for the object instance (note: not class, only this specific object instance).

The following are the main built-in objects (i.e., objects that are automatically available to you).

  • Array
  • Data
  • Object
  • Error
  • Function
  • RegExp

Declaring Objects

Use the new operator:

var o1 = new Object();
o1.prop1 = "something";
o1.prop2 = 101;

Using object literals we can create the exact equivalent of the above:

var o1 = { prop1: "something", prop2 : 101 } 

Note how we don't need quotes around the object properties.

This looks a little bit like a dictionary in some scripting languages like python, and in fact we can use an object in that manner most of the time.

Declaring Arrays

Can declare using the new operator (var a1 = Array(1,2)) or using array literals (var a1 = [1, 2] - identical to the previous instantiation using new).

Declaring Functions And Function Expressions

Declarations

A function declaration is a lot like a function declaration in any language and will look familiar:

my_new_func(123);

function my_new_func(param)
{
   // Do something
}

You might notice in the above example that the function is actually called before it is declared. This would be unexpected if you were thinking in C terms, where a function must be declared before it can be used. So what's happening? The reason the above works is that declared functions are hoisted to the top of the enclosing scope. This is why, in the example the function could be called before it was declared.

Function declarations are hoisted to the top of the enclosing scope.

Expressions

In JavaScript functions are first class objects and can be created as such. The most common syntax for this is:

my_new_func(123); //< This is an error!

var my_new_func = function(param) {
   // Do something
};

my_new_func(123); // This is OK.

Note the trailing semi-colon after the function definition. It's important not to miss this. The function object is created from the function literal and a reference to it stored in the variable my_new_func.

Note, however, that using the function before it is defined using an expression will result in an error. Why is this? It is because function expressions are not hoisted to the top of the current scope!

Function expressions are NOT hoisted to the top of the enclosing scope. They can only be used after they are defined.

Parameters

Functions can have any number of parameters and can be called with fewer or more parameters than which they are defined! When called with fewer the latter parameters are automatically set to "undefined". For example:

function dummy(a,b,c) {
   console.log(a);
   console.log(b);
   console.log(c);
}

dummy(123, "jeh-tech");
//Outputs:
//   123
//   jeh-tech
//   undefined

Using this fact, default values for parameters can be created. For example, let's say we want to give the parameter c in the above example a value of "tech-jeh". We can re-write the function as follows:

function dummy(a,b,c) {
   c = typeof options === 'undefined' ? "tech-jeh" : c;
   console.log(a);
   console.log(b);
   console.log(c);
}
dummy(123, "jeh-tech");
//Outputs:
//   123
//   jeh-tech
//   tech-jeh

However, this can be written much more neatly as follows:

function dummy(a,b,c) {
	c = c || "tech-jeh"; // Looks better!
   ... <snip> ...
}

Because functions are first class objects they have properties, which you can query from inside your function. One property bound to a function when it is called is the arguments object.

function dummy(a,b,c) {
   console.log(dummy.length);            // Expected #arguments
   console.log(dummy.arguments.length);  // Actual #arguments
   console.log(dummy.arguments.callee);  // Object reference this this function
   for(var idx=0; idx < dummy.arguments.length; ++idx) {
      console.log(dummy.arguments[idx]); // The nth function argument
   }
}

dummy("param1", "param2", "param3", "param4")
//Ouputs:
//   3
//   4
//   function dummy(a, b, c)
//   param1
//   param2
//   param3
//   param4

One use for arguments.callee I've seen is in the use of timer callback functions...

setTimeout( function() {
...
if (condition)
   setTimeout(arguments.callee, timeInMilliseconds);
...
});

Other points to note include:

  • Functions can have arbitrary number of parmeters
  • function_name.length gives number of arguments function expects. I.e., number of arguments explicity listed in signature. Function can have more or less.
  • You can access arbirary arguments using function_name.arguments[] array.
  • Functions can't be overloaded as lack of a solid parameters list means lack of real signature.

Object Methods: Properties That Reference Functions & Changing "this"

Object methods are just properties that reference functions. When an object method is called it's this reference is set to "point" to the associated object, as we saw briefly in the section on scope.

It is possible to change the object to which the this reference is bound when calling a function using the function method call() (remember functions are first class objects so have methods and properties associated with them).

  • func_name.call(this_value, arg1, ..., argN)
    Calls the function but binds this to this_value, overriding its default binding.
  • func_name.apply(this_value, [arg1, ..., argN])
    Like call() except function parameters specified in array. Useful if you want to dynamically build the argument list.
  • func_name.binc(this_value, param1, ..., paramN)
    Creates a new function object using func_name as the template with the function#s this value bound to this_value, overriding the default. It optionally also binds some of the parameters.
OBJECTS:
--------
Test For Object Properties
	property_name in object_name
		Does not evaluate the property just says if present
		Checks for bowth own and prototype properties
	obj.hasOwnProperty() to check for specifically own properties

Remove property
	delete obj.property_name
	NOTE: This only works on own properties

Enumerate properties:
	for(property in object) {...} or
	var props = Object.keys(object); for(var i=0; i < props.length; ++i) { ... }
	The for-in loop also enumerates prototype properties, while Object.keys() returns only own (instance) properties

Constructor:
	A constructor is simply a function that is used with new to create an object. 

	Constructors allow you to initialize an instance of a type in a consistent
	way, performing all of the property setup that is necessary before the object can be used.

	Make sure to always call constructors with new; otherwise, you risk
	changing the global object instead of the newly created object.

	Function name with capital is convention to represent object

	Eg

		var cat = {
			name: "kitty",
			speak: function() { console.log(this.name + " says meow"); }
		}

	Translates into

	function Cat(name) {
		this.name = name;
		this.speak = function() { 
			console.log(this.name + " says meow"); 
		};
	}

	
Prototype:
	A recipe for a object.
	The shared nature of prototypes makes them ideal for defining methods
	once for all objects of a given type. It’s much more efficient to put 
	the methods on the prototype and then use this to access the current instance.

	function Person(name) {
		this.name = name;
	}
	Person.prototype.sayName = function() {
		console.log(this.name);
	};

	Or on mass
	
	Person.prototype = {
		constructor: NAME, // Using the object literal notation to overwrite the prototype changed
					the constructor property so that it now points to Object u instead of Person.
					This happened because the constructor property exists on the prototype,
					not on the object instance. When a function is created, its prototype property
					is created with a constructor
					property equal to the function.
		sayName: function() { ... },
		...
	}

	Checking for properties in the prototype...

	function hasPrototypeProperty(object, name) {
		return name in object && !object.hasOwnProperty(name);
	}

	Each instance has pointer back to prototype through internal property [[Prototype]]
	You can read the value of the [[Prototype]] property by using the Object.getPrototypeOf()
	method on an object: 
		var prototype = Object.getPrototypeOf(object);


	You can also test to see if one object is a prototype for another by
	using the isPrototypeOf()
		var object = {};
		console.log(Object.prototype.isPrototypeOf(object));



	You can also store other types of data on the prototype, but be careful
	when using reference values. Because these values are shared across
	instances, you might not expect one instance to be able to change values
	that another instance will access.


	


Inheritance - Prototype Chaining:

	Prototype is also an object, it has its own prototype and inherits properties
	from that. This is the prototype chain: An object inherits from its prototype,
	while that prototype in turn inherits from its prototype, and so on.
		
	Methods inherited from Object:
	valueOf() - lets you do +/-/<gt; etc operations by returning value
	toString() - Called if valueOf() returns reference instead of primative. Also when JS expects string.
	propertyIsEnumerable()
	hasOwnProperty()
	ifPrototypeOf()

	Object.prototype - DONT CHANGE: All objects inherit from Object.prototype by 
	default, so changes to Object.prototype affect all objects.

	Simple Inheritance
		Explicitly specify [[Prototype]] with the Object.create(obj-for-proto, [prop-descr]) method:
		
		var book = {
			title: "The Principles of Object-Oriented JavaScript"
		};
		// is the same as
		var book = Object.create(Object.prototype, {
			title: {
				configurable: true,
				enumerable: true,
				value: "The Principles of Object-Oriented JavaScript",
				writable: true
			}
		});

		Or do MyObject.prototype = new OtherObject();
		MyObject.prototype.constructor = MyObject;

		Or MyObject.prototype = Object.create(OtherObject.prototype, {
			constructor: {
				value: MyObject;
			}});
	
		Always make sure that you overwrite the prototype before adding properties to it,
		or you will lose the added methods when the overwrite happens.



	Calling SuperClass Constructor:
		function Rectangle(length, width) {
			this.length = length;
			this.width = width;
		}
		Rectangle.prototype.getArea = function() {
			return this.length * this.width;
		};
		Rectangle.prototype.toString = function() {
			return "[Rectangle " + this.length + "x" + this.width + "]";
		};
		// inherits from Rectangle
		function Square(size) {
			Rectangle.call(this, size, size);
			// optional: add new properties or override existing ones here
		}
		Square.prototype = Object.create(Rectangle.prototype, {
			constructor: {
				configurable: true,
				enumerable: true,
				value: Square,
				writable: true
			}
		});


	Call supertype method:
		// call the supertype method
		Square.prototype.toString = function() {
			var text = Rectangle.prototype.toString.call(this);
			return text.replace("Rectangle", "Square");
		};

Module Pattern:
	The module pattern is an object-creation pattern designed to create singleton
	objects with private data. The basic approach is to use an immediately
	invoked function expression (IIFE) that returns an object. An IIFE is a function
	expression that is defined and then called immediately to produce a
	result. That function expression can contain any number of local variables
	that aren’t accessible from outside that function. Because the returned
	object is defined within that function, the object’s methods have access
	to the data.

	var yourObject = (function() {
		// private data variables
		return {
			// public methods and properties
		};
	}());

Scope safe constructors:
	function Person(name) {
		if (this instanceof Person) {
			// called with "new"
			this.name = name;
		} else {
			// called without "new"
			return new Person(name);
		}
	}

		

HTML 5 Canvas

W3C Reference.

MDN Canvas Tutorials, which are rather good!

Picture explainging rendering of HTML5 canvas lines with an odd lineWidth on integer coordinates Picture explainging rendering of HTML5 canvas lines with an odd lineWidth on half coordinates Picture explainging rendering of HTML5 canvas lines with an odd lineWidth on half coordinates

Your browser does not support the HTML5 canvas tag.

TODO: Read the following...
http://www.html5rocks.com/en/tutorials/canvas/performance/
https://dev.opera.com/articles/html5-canvas-basics/

Realllllly cool use of Cavas: JavaScript NES Emulator and Spectrum emulator.

RECTANGLES
----------

filling, stroking and clearing

fillRect(x,y,w,h)   - fills rect
strokeRect(x,y,w,h) - draws outline. Uses current strokeStyle, lineWidth lineJoin and miterLimit setings.

clearRect(x,y,w,h)

fillStyle is the colour we'll fill with
strokeStyle is the outline colour

Current canvas state includes
- Trsnformations
- Clipping regtion
- Attributes
	 - globalAlpha
	 - globalCompositeOperation
	 - strokeStyle
	 - textAlign
	 - textBaseLine
	 - lineCap, lineJoin, lineWidthm miterLmiit
	 - fillStype
	 - font
	 - shardowBlur, shadowColor, shadowOffsetX, shadowOffsetY


Not part of state - the current path/bitmap being manipulated.

Save and restore canvas state using context.save() and context.restore()

Paths
-----

Use to create arbirary shapes: a list of points and lines to be drawn between them.

Only one current path per context state. Current path is not saved when context.save() is called.

Current path concept to transform ONLY the current path on the canvas.

ctx.beginPath(), ctx.closePath() - start and stop a path. Current transformation effects only things drawn in the current path.

ctx.moveTo(x,y) - move pen without drawing
ctx.lineTo(x,y) - draw line from current pen position to new position

ctx.stroke()    - actually fillin the lines.


ctx.lineWidth, lineJoin (miter, bebel, round), lineCap (butt, round, square)

ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise)

ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
ctx.quadraticCurveTo(cpx, cpy, x, y)

Clipping
--------
Combining the save() and restore() functions with the Canvas clip region limits the
drawing area for a path and its subpaths

transforms
-----------
apply to shapes and paths drawn after the setTransform() or other
transformation function call

We must move the point of origin to the center of our shape to rotate it around its own
center

ctx.setTransform(1,0,0,1,0,0); // Identity
// then set point of origin
ctx.translate
// then rotate
ctx.rotate

Gradients
--------
ctx.fillStyle = "black"
ctx.fillStyle = "#rrggbb"
ctx.fillStyle = rgba(r,b,g,alpha)
ctx.fill()

g = ctx.createLinearGradient(x1, y1, x2, y2);
	- draws gradient along line defined by (x1,y1) to (x2,y2)

Next add color stops
g.addColorStop(where, 'rgb(r,g,b)');
	where is a number between 0 and 1
	the second parameter is evaled by the function

then set fillStyle
ctx.fillStyle = g

This can also be applied to the strokeStyle
ctx.strokeStyle = g