Notes are actually on:
- callbacks
- objects
- prototype
- namespaces
Notes are actually on:
/* | |
* CALLBACKS | |
*/ | |
// Callbacks functions are widely used for async execution, event listener / | |
// event hanlder | |
// A callback function is a function that is passed to another function | |
// as a parameter, and the callback is called inside this another function. | |
// As we know, closures have access to the containing functions scope, | |
// so the callback function can access the containing functions variables, | |
// and even the variables from the global scope. | |
/* I. ANONYMOUS CALLBACK */ | |
var a = ["a", "b", "c"]; | |
a.forEach(function (value, index) {// we have passed an anonymous functions as parameter | |
var x = index + 1; | |
console.log(x + ". " + value); | |
}); | |
/* II. CALLBACK WITH NAMED FUNCTION */ | |
function getDataAndProcess(callback){ | |
var data = "Hello"; | |
if(callback && typeof(callback) === "function") { // ensure that the callback is actually a function | |
return callback(data); | |
} | |
} | |
function process (data) { | |
return data.substr(0,2); | |
} | |
var processedData = getDataAndProcess(process); | |
console.log(processedData); // "He" | |
// if we use the this object in a callback function, we have to modify | |
// how the callback function is executed to preserve the this object context. | |
// we need to be careful aswell for the 'callback hell' effect, | |
// e.g many nested callbacks. Better name the function and sctructure the code. |
/* | |
* OBJECTS | |
*/ | |
// Javascript fundamental datatype is object. Any value other than string, number, boolean values, | |
// null or undefined is an object. | |
// Every objects has class, prototype and extensible attributes | |
/* I. OBJECTS ARE MUTABLE AND MANIPULATED BY REFERENCE */ | |
var x = { x:2 }; | |
var y = x; // y holds a reference on x, not a copy | |
y.y = 2; | |
console.log(x); // Object {x: 2, y: 2} | |
/* Create an object */ | |
var empty = {}; // empty object | |
var track = { // literal way, you can also nest properties | |
artist: "netsky", | |
title: "Your Way", | |
label: "Hospital Records" | |
} | |
var empty = new Object(); // = {}; create an object with new | |
var array = new Array(); // = []; | |
var obj = Object.create(empty); // first arg take the prototype of empty to inject in obj, | |
// can use a second arg to define the properties of obj | |
/* II. TEST AN OBJECT PROPERTY */ | |
"artist" in track // true | |
track.hasOwnProperty("artist") // true, would be false if "artist" was an inherited property | |
/* III. QUERY AN OBJECT PROPERTY */ | |
var title = track["title"]; // access properties with associative array, where the property name is a string | |
var label = track.label; // or dot notation (.) | |
console.log(track.lyrics) // undefined, but doesn't throw an exception | |
var lyricsLen = // this will throw a typeError exception, because lyrics is undefined. | |
track.lyrics.length; | |
var lyricsLen = // this is a concise way of protecting property access, can be done with if {} aswell | |
track && track.lyrics && track.lyrics.length; | |
var book = { // Considering the following code, I find access properties with associative array | |
author0: "a", // useful in this case. You can't do this with the . expression, because the property | |
author1: "b", // is an identifier, not a string. | |
author2: "c" | |
} | |
var enumAuthors = function(book) { | |
var authorCounter = 0; | |
for(property in book) { // enumerate properties ! | |
if(property.indexOf("author") !== -1 ) { | |
authorCounter++; | |
} | |
} | |
var authors = ""; | |
for(var i = 0; i < authorCounter; i++) { | |
if(i == authorCounter - 1) { | |
authors += book["author" + i]; | |
} else { | |
authors += book["author" + i] + ", "; | |
} | |
} | |
console.log(authors); | |
} | |
enumAuthors(book); // a, b, c | |
// We have seen that you can enumerate properties with a simple for loop, | |
// but ES5 define the following | |
Object.keys(track); // ["artist", "title", "label"] array of the enumerable own properties | |
Object.getOwnPropertyNames(track); // same as .keys(), but return an array of all the own properties | |
// it makes sense because ES5 provide a way to make a property non-enumerable | |
/* IV. DELETE AN OBJECT PROPERTY */ | |
// the delete operator deletes the object OWN properties, not inherited ones. | |
// for doing so, delete the property in the prototype. Be careful, it affect | |
// every objects that inherits from that prototype. side-effect ! | |
delete track.label; | |
console.log(track); // Object {artist: "netsky", title: "Your Way"} | |
// You can't delete properties like the prototype, because they are read only | |
/* V. OBJECT SERIALIZATION/DESERIALIZATION */ | |
var s = JSON.stringify(track); // NaN, Infinity, -Infinity serialize to null | |
var ptrack = JSON.stringify(s); // Date are serialized to ISO date string | |
// Function, RegExp and Error objects and undefinined | |
// can't be serialized. | |
/* VI. OBJECT METHODs REF */ | |
toString(); | |
toLocaleString(); // format date and number according to local settings | |
toJSON(); // JSON.stringify() looks for a toJSON() method on any object passed | |
valueOf(); | |
/* | |
* PROTOTYPE | |
*/ | |
// WARNING: for better understanding of prototype, please don't give a single fuck | |
// to the pseudo __proto__ property of Mozilla JS implementation, it is non-standard. | |
/* I. PROTOTYPE PROPERTY */ | |
// There is a prototype property on every function, empty by default | |
// and not enumerable (no for/in loop) | |
var getHello = function (){ | |
return "Hello"; | |
} | |
console.log(getHello.prototype) // Object {}; | |
// That said, Firefox and most versions of Chrome have a | |
// __proto__ wrapper property that allow acess. don't use it | |
// We use the prototype property to apply inheritance | |
function pdfDoc(doc){ | |
this.doc = doc; | |
} | |
pdfDoc.prototype.print = function () { | |
console.log(this.doc); | |
} | |
var pdfDoc = new pdfDoc(doc); | |
pdfDoc.print(); | |
/* II. Prototype attribute */ | |
// The prototype attribute is set when an object is created. | |
// Prototype Attribute for Ojbects created with literal or new Object | |
var x = { x:1 }; | |
var y = new Object(x); | |
x.isPrototypeOf(y); // true | |
Object.prototype.isPrototypeOf(y); // true | |
x.prototype // undefined, wtf ? | |
// because when creating like {x:1}, you're actually | |
// creating an instance of the Object constructor | |
Object.getPrototypeOf(x); // Object {} | |
// because the prototype of the Object constructor | |
// is an Object. The Object prototype is itself | |
// an object | |
// we can conclude that constructors have .prototype and instances | |
// have Object.getPrototypeOf() | |
Object.getOwnPropertyNames(Object.getPrototypeOf(x)); | |
// ["constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", | |
// "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", | |
// "__defineSetter__", "__lookupSetter__"] | |
// We can see here that all objects created with literals or object ctor | |
// inherits from Object.prototype. |
/* | |
* NAMESPACES | |
*/ | |
// So this is my attempt at creating clean, self-injecting namespace in javascript | |
// using IIFE (Immediately-invoked function expression). | |
// Be aware that now it seems there is plenty of things and lib to deal | |
// with this like requireJS / CommonJS | |
;(function(ns) { | |
var calc = (function(ns){ | |
ns.addition = function() { | |
var total = 0; | |
for(var i = 0; i < arguments.length; i++) { | |
total += arguments[i]; | |
} | |
return total; | |
}; | |
ns.multiply = function() { | |
var total = 1; | |
for(var i = 0; i < arguments.length; i++) { | |
total *= arguments[i]; | |
} | |
return total; | |
}; | |
}) (ns.calc = ns.calc || {}); | |
}) (window.myLib = window.myLib || {}); | |
console.log(myLib.calc.addition(1,2,3,4)); // 10 | |
console.log(myLib.calc.multiply(1,2,3,4)); // 24 | |
console.log(myLib); // Object {calc: Object} | |
console.log(myLib.calc); // Object {addition: function, multiply: function |