Javascript Notes
Just notes from various books/websites on JavaScript. Have tried to reference as thoroughly as possible.
Page Contents
References
Useful Resources
- https://jsconf.com/
- https://javascriptweekly.com/
- https://frontendfoc.us/
- http://jstherightway.org/
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.
Loops
for ... of
Ref: Loops and Iteration.
Iterate over iterable objects:
my_array = ["This", "is", "a", "test"]; for (let [idx, array_entry] of my_array.entries()) { // entries() returns an Array Iterator console.log(`${idx} -> ${array_entry}`); } // Outputs: // 0 -> This // 1 -> is // 2 -> a // 3 -> test
Scope In JavaScript
Scope is the context in which code is executed, and there were three types, now 4, in JavaScript.
- global scope,
- local scope (aka "function scope"),
- eval scope,
- block scope (>=ES6) - use
let
orconst
.
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
Javascript objects are just dictionaries that map keys to values. A property is the key name that maps to its value.
New Operator
Use the new operator:
var o1 = new Object(); o1.prop1 = "something"; o1.prop2 = 101;
Object Literals
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.
Object.create()
Allows the prototype object for the object being create to be specified:var LiteralClassDef = { myFunc: function() { console.log(this); } } var blah = Object.create(LiteralClassDef); blah.myFunc();
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.bind(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.
Cookies
AJAX
Server Sent Events
Websockets
REST
GraphQL
State
https://indepth.dev/posts/1488/state-machines-in-javascript-with-xstate
Rough Notes
Javscript Internals and Promises/Async Functions
REF -- https://www.udemy.com/course/the-complete-javascript-course/learn JAVASCRIPT INTERTALS ==================== JavaScript hosted in an enironment. E.g. your browser, or nodejs. The host, has a Javascript engine that takes the code and executes it. E.g. of engines include Google V8, rhINO,and Spider Monkey to name just a few. All JS code must run inside something... this is the execution context. It is a "wrapper" or "container" of sorts, that stores variables and in which a piece of code is evaluated and runs. See http://dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts/. From SO - https://stackoverflow.com/a/9384894/1517244 and https://stackoverflow.com/a/7722057/1517244 Execution context is a concept in the language spec that, in layman's terms, roughly equates to the 'environment' a function executes in; that is, variable scope, function arguments, and the value of the this object. The context stack is a collection of execution contexts. Execution context is different and separate from the scope chain in that it is constructed at the time a function is invoked (whether directly – func(); – or as the result of a browser invocation, such as a timeout expiring). The execution context is composed of the activation object (the function's parameters and local variables), a reference to the scope chain, and the value of this. The call stack can be thought of as an array of execution contexts. At the bottom of the stack is the global execution context. Each time a function is called, its parameters and this value are stored in a new 'object' on the stack. From the Spec, with some - https://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf: An execution context is a specification device that is used to track the runtime evaluation of code by an ECMAScript implementation. At any point in time, there is at most one execution context per agent that is actually executing code. This is known as the agent's running execution context. All references to the running execution context in this specification denote the running execution context of the surrounding agent. The execution context stack is used to track execution contexts. The running execution context is always the top element of this stack. A new execution context is created whenever control is transferred from the executable code associated with the currently running execution context to executable code that is not associated with that execution context. The newly created execution context is pushed onto the stack and becomes the running execution context. An execution context contains whatever implementation specific state is necessary to track the execution progress of its associated code. Each execution context has at least these state components: 1. Code evaluation state All state needed to perform, suspend, and resume evaluation of the code associated with this execution context 2. Function. If this execution context is evaluating the code of a function object, then the value of this component is that function object. If the context is evaluating the code of a Script or Module, the value is null. 3. Realm The Realm Record from which associated code accesses ECMAScript resources. 4. Script or Module The Module Record or Script Record from which associated code originates. If there is no originating script or module, as is the case for the original execution context created in InitializeHostDefinedRealm, the value is null. Execution contexts for ECMAScript code have these additional state components: 5. Lexical Environment Identifies the Lexical Environment used to resolve identifier references made by code within this execution context. 6. Variable Environment Identifies the Lexical Environment whose EnvironmentRecord holds bindings created by VariableStatements within this execution context. The DEFAULT EXECUTION CONTEXT is the GLOBAL EXECUTION CONTEXT - Code not inside any function - Associated with the global object (e.g., Window if running in a browser) Also, callbacks from from things like timeouts execute in the GLOBAL execution context. In the browser console type... > var b = 39393939393; < undefined > > b < 39393939393 > # Now we can see that code in the global execution context belongs to the global object, which > # for a browser, is the window object. > window.b < 3939393939 Same with functions, for example... > function JEH() { var a; } < undefined > JEH < f JEH() { var a; } > window.JEH < f JEH() { var a; } EXECUTION CONTEXT OBJECT: 2 phases: creation and then execution. | +---- Variable Object | Code is scanned at load time for function declarations. For each function an entry into the VO is made that records | things like the arguments passed into the function. Also done for variables, which are added as properties to the | VO and initially set to undefined. This is refered to as HOISTING - they are available before the execution phase | starts, which is why we can write: | my_func(); | ... | function my_function() { ... } | | Note, how this wouldn't work if we used a function variable, because although the VARIABLE my_func is hoisted, | it is hoisted and undefined (until it is defined lol). | my_func(); # Can't call undefined | var my_func = function { ... }; | | | Another example of variable hoisting... | function b() { | console.log(bbb); // OK: bbb is defined in environment VO, with a value of undefined | var bbb = 10; | } | b(); // Outputs "undefined" | | function c() { | console.log(ccc); // ERROR: ccc is not defined (not in environment VO) | ccc = 10; | } | c(); // Raises a ReferenceError exception! | +---- Scope Chain | Scoping determines where, in terms location in the code, a variable is accessed. A variable scoped locally to a function | can be accessed within that function, but not in the scope outside that function for example. However, a function A closed | by another function B, can access variables in B's scope. Or a normal function can access variables from the global scope. | | JS is lexically scoped which means that scope is determined by somethings position in the code. | +---- "This" variable. Set in the creation phase. What "this" refers to depends on the context. In the global context it refers to the global object (window for browsers). In a regular function context it also refers to the global object. For a method call this points to the object that is calling the method. NOTE: This is not assigned a value until a function where it is defined is actually called, Thus, "this" is NOT lexically scoped! E.g.: function test1() { console.log(this); } test1(); // Outputs Test1 == [object Window] var test2 = { my_method: function() { console.log("Test2 == " + this); function test3() { console.log("Test3 == " + this); } test3(); }, }; test2.my_method(); // Outputs Test2 == [object Object] // Test3 == [object Window] << NOTE: MAY SURPRISE YOU! EXECUTION STACK = order in which functions are called SCOPE CHAIN = order in which functions are written in the code - i.e. their lexical relationship to one another. Thus the execution stack does NOT define where variables can be accessed... it is the scope chain that does this! The execution context will store the scope chain, but do not effect the scope chain. PROMISES ======== Callback hell ------------- function get_pr_requests(account_details) { ask_server_for_pr_reqs( server_address, account_details, (status, pr_list) => { if (status == OK) { pr_list.map( pr_item => { ask_server_for_pr_details( server_address, account_details, (status, pr_deets) => { ask_server_for_files( ..., (status, file_list) => { file_list.map( file => { ask_server_for_file( ... (status, file) => { .... and so one ... nesting deeper and deeper! } ) }) } ) } ) }) } } ); } This continual nesting of functions makes it very hard to read and understand this code. This triangular shape of continuall nested callbacks is what is refered to as callback hell. Without the ES6 arrow function it would look even worse as the binding of the "this" keyword would also need to be managed! Promises to the rescue (>=ES6) ------------------------------- Promise: - Object that keeps track about whether a certain event has happened already. - Determines what happens after the event has happened - Implements the concept of a future value that we are expecting Promise states: PROMISE PRODUCED | | v PENDING ---event---> SETTLES/RESOLVED ---succcess---> FULFILLED | +------------failure----> REJECTED JS: const my_promise = new Promise( executor ); ^^^^^^^^ This is a function that is called as soon as the promise is created and usually executes something ASYNCHRONOUS like a Fetch. The executor function takes two arguments: 1. A CALLBACK function for when the executor wants to inform the promise that the event it was handling was succcessfull. I.e., it wants to RESOLVE the promise. It takes one argument, which is the result that the promise should return (the future value that was expected). 2. A CALLBACK function for when the executor wants to inform the promise that the event it has handling failred. It wants to REJECT the promise. EG: // // CREATE a promise // const get_pr_requests = new Promise((resolve, reject) => { ask_server_for_pr_reqs( //< This is the async function our executor will run server_address, account_details, (status, pr_list) => { //< This is the function "ask_server_for_pr_reqs" calls back // when it has finished doing its work. if (status == OK) { resolve(pr_list); } //< We then call the Promise resolve() or else { reject(status); } // reject() depending on whether // "ask_server_for_pr_reqs" succeeded. } ) }); // // Create another promise, this time as a function that returns a promise. // const get_pr_deets = pr_id => { return new Promise( (resolve, reject) => { ask_server_for_pr_details( ..., (status, pr_deets) => { if (status == OK) { resolve(pr_deets); } else { reject(status); } } }); }; // // CONSUME a promise by using then() and catch() methods. // then() is the callback to execute when the promise is RESOLVED // catch() is the callback to execute when the promise is REJECTED // get_pr_requests.then( pr_list => { // pr_list is what get_pr_requests passed to resolve() // The promise was RESOLVED - it completed successfully. return get_pr_deets(pr_list[0]); // Return a NEW PROMISE allows us to **CHAIN** promises // (rather than using the previous pattern of continually // nesting callbacks, which is what lead to callback hell) }).then( (pr_deets) => { // Handle the promise returned by the previous next() - this is CHAINING! }).catch( error => { // The promise was REJECTED console.log(error); }); ASYN / AWAIT (>= ES8) ====================== Makes it easier to _consume_ promises. The promise creation still remains the same... async function func_name(...) { ... } // New type of JS function that is asynchonrous // so will keep running in the background on another thread // the result of which will be popped back into the event // Q when its ready. An async function keeps running the the background, and importantly only in async functions can await's be used. Importantly, like the previous promise consumption, the call to the asyn function does not block... instead it just chuggs away in the background. // The function will keep executing in the background. An await will block until the promise // is fulfilled. async function load_pr_stuff() { try { const pr_reqs = await get_pr_requests; // CONSUME promise using await. // ^^^^ // instead of .next() // ^^^^ // pr_reqs gets the RESULT of the promise. const pr_deets = await get_pr_deets(pr_reqs[0]); // Like the chained .next() above. } catch (error) { // Any REJECT is caught as an error. console.log(error); // Handle the error somehow } } This turns a ton of callbacks or chained promisises into something like looks a lot more proceedural and is therefore a lot easier to grok! NICE NICE NICE! An async function returns a promise. So if, inside the async you return something of interest, you can get at it using the .next() method: load_pr_stuff().next(...) Basically async functions let us go from X.then( a => { return someFuncA(a); // Return new promise } ).then ( b => { return someFuncB(b); // Return new promise } ) ... .then ( z => { return someFuncZ(z); // Return new promise } ) To: async function A() { const a = await X() ... const b = await someFuncA(a); ... const c = await someFuncB(b); ... const z = await someFuncY(y); return z; } Which is a little neater and allows our reasoning to be more "linear" and flow, rather than having to think about the "house keeping" of callbacks. AJAX WITH PROMISES AND AWAIT ============================ Can use XMLHTTPRequest interface. There is a newer version of this called FETCH. XMLHttpRequest has better browser support because it is older, but FETCH is more modern. fetch(URL) // Returns a promise... yay! If you see error containing "No-Access-Control-Allow-Origin" it is talking about a JS policy that prevents a page making AJAX requests to a domain different to its own domain. Cross-Origin Resource Sharing (CORS). See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS. " Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin, access to selected resources from a different origin. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) from its own... ...For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts. For example, XMLHttpRequest and the Fetch API follow the same-origin policy. This means that a web application using those APIs can only request resources from the same origin the application was loaded from unless the response from other origins includes the right CORS headers. " Can use a proxy to get around this - e.g., crossorigin.me - it is a CORS proxy that you can use for free To use prefix the URL of the API end-point you are using with "https://crossorigin.me/". Eg, to use the metaweather free API, which does not implement CORS use: fetch("https://crossorigin.me/https://metaweather.com/api/location/<num>").next(...)...; So, to continue with FETCH: fetch(URL).next( result => { console.log(result); return result.json(); // Returns a promise that should resolve to the JS object created // from the JSON string returned by the API. }).next( jsonObj => { // Do something with the returned data which is now represented as a JS object for us. }).catch ( error => { console.log(`It failed due to ${error}`); }); Or... use await: async function load_pr_stuff() { const result = await fetch(URL); const data = await result.json(); return data; // < Returns a promise! } load_pr_stuff.then( data => console.log("The final data is " + data) ); // ^^^ // Remember this is the way to get the final promise returned by the async function
Javscript Objects, Prototical Inheritance etc
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
MDN Canvas Tutorials, which are rather good!
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