Skip to content

Instantly share code, notes, and snippets.

@shoaibi
Last active August 29, 2015 14:23
Show Gist options
  • Select an option

  • Save shoaibi/eed26413849b76a65fcc to your computer and use it in GitHub Desktop.

Select an option

Save shoaibi/eed26413849b76a65fcc to your computer and use it in GitHub Desktop.
Javascript notes

General

  • Comment
    • Single line comment: //
    • Multiline comment /* */
  • Combining multiple initialization is better as JS Engine would be faster at executing a single statement
var first = 10,
    second = 15,
    third = "third";
  • console.dir() to print something as is, without quotes and such.
  • For comparison conditions that involve stuff like array length, initialize another variable with the length property instead of computing like on every single iteration
for (var i=0; i < arr.length; i++);

is slower than

for (var i=0, l=arr.length; i < l; i++);

Truthy/Falsely:

  • '0' is false (unlike PHP)
  • 'false' is true
  • [] is true (unlike PHP)
  • { } is true

Types

  • number(integers as well as floating point), string, boolean, Object(array, object, Date, RegExp, null), function.
    • null and undefined types can't contain any values.
  • typeof to get the type of anything.
  • No isDate, isString functions (there is Array.isArray() though)
    1. typeof but this fails as it returns Object for all objects including user-defined types and null.
    2. instanceof This fails in case of iframes.
    3. Duck typing e.g. check typeof of a property/method of the object at hand and ensure it is not "undefined". This could also fail where we are checking for a property/method that exists across multiple types or if we send in a user-defined object with just that property/method.
    4. return Object.prototype.toString.call(myString) === '[object String]'; but this would also fail for use-defined objects

function type(obj){ var text = obj.constructor.toString() return text.match(/function (.*)(/)[1] }

This is going to be slow (which we can improve by using ```indexOf()``` and ```substr()```), also open to shadowing:
  ```javascript
Array.toString = function(){ return "function NotArray(){ }" }
type([1,2,3]) // "NotArray"

and would not perform well with user types:

var f = function Animal(){ "something" }
var g = function Animal(){ "something entirely different" }
type(new f) // "Animal"
type(new g) // "Animal"
  • MDN uses fourth option as polyfill recommendations
  • Type conversion
    • !! to convert anything to a boolean // or the explicit Boolean(x) works too
    • Convert number to string:
      • 6 + ""; // "6" , internally gets resolved to (6).toString() + ""
      • String(6)
      • (6).toString() , fastest per http://jsperf.com/number-to-string/2
        • toString() behavior:
          • [10,20] // "10,20"
          • true // "true"
          • false // "false"
          • { } // [Object object]
          • rest are as expected.
    • Converting strings to Numbers:
      • Parse number from string:
        • parseInt("12a11", 10); // 12
        • parseInt("s123", 10); // NaN
        • parseInt() can also work on floats and return the floor value.
      • Parse float from a string:
        • parseFloat("3.14e1", 10); // 3.14
      • Parse a number(whether it is float or integer)
        • Number("123"); // 123
        • Number("3.14519"); // 3.14519
        • Number(""); // 0
        • Number(" "); //0
        • Number("yellow"); // NaN
        • + "61.2"; // or - "61.5" both will return 61.5
        • "6" - 0; // or "6" / 1; or "6" * 1;
    • Binary Addition operator unique behavior
      • 4 + 5 + "7" + 6 + 5 // "9765"
        • This behavior is only unique to addition/concatenation operator. For deduction, multiplication or division string will be converted to a number

String

  • length
  • indexOf(key,[ offset[)
  • lastIndexOf(key[, fromIndex])
  • search(regex)
    • use indexOf as that is faster, unless we really need to use regex
  • charAt(index)
  • startsWith(searchString[, position])
  • endsWith(searchString[, lastPosition])
  • slice(beginSlice[, endSlice])
    • returns new string
  • split([separator[, limit]])
    • returns array, missing separator: whole string as one array element, empty string separator: character array
  • substring(indexA[, indexB])
    • returns sting, order of parameters is not relevant, same result is return regardless. non-int or negative are treated as 0, greater than str.length is treated as str.length implicitly
  • substr(start[, length])
    • returns sting, better version of substring() with proper support for negative indexes, parameter order does matter, both indexes are inclusive.
  • toLowerCase()
    • returns new string
  • toUpperCase()
    • returns new string
  • trim()
    • returns a new string with whitespace chopped of. trimLeft() and trimRight() exist but are not part of standard, may be use polyfills to use those if really needed.
  • replace(str|regex, replacementStr|replacementExpr);
    • returns new string. regex e.g. /matchThis/gi (gi = global and case insensitive), replacement could be a single string or use replacement patterns with $n where n is the match found

Arrays

  • Most function take a callback of the format
function(value, index, array) {
}
  • length
  • concat(value1[, value2[, ...[, valueN]]])
    • returns a new array
  • filter(callback[, thisArg])
    • returns a new array
  • forEach(callback[, thisArg])
  • indexOf(searchElement[, fromIndex = 0])
  • join([separator = ','])
    • returns string
  • lastIndexOf(searchElement[, fromIndex = arr.length - 1])
  • map(callback[, thisArg])
    • returns a new array after applying callback
  • pop()
  • push(element1, ..., elementN)
    • returns new length
  • reduce(callback[, initialValue])
    • callback takes: (function(previousValue, currentValue, index, array), tries to merge all values and return a single value
  • reverse()
    • reverse the order, in place
  • shift()
    • removes and returns first element
  • unshift([element1[, ...[, elementN]]])
    • adds elements at the start, returns new length
  • slice([begin[, end]])
    • returns sliced array, end not inclusive
  • every(callback[, thisArg)
    • tests if every element passes a test
  • some(callback[, thisArg])
    • tests if some elements pass a test or not
  • sort([compareFunction])
    • by default sorts by unicode values
  • splice(start, deleteCount[, item1[, item2[, ...]]])
    • delete and/or add elements in an array in place, returns array of deleted items

Date

  • Comparison operators of < and > work as expected
  • == or === would not work as date objects would be different even if they have same time.
    • A workaround would be to compare equality of getTime() of both dates
  • Constructor
    • new Date()
      • Uses the Timezone from the vm's box, say client in case of a browser
      • Variations of constructor:
        • new Date(year, month, date, hours, minutes, seconds, milliseconds)
          • Months start at 0
          • Hours are 0-23
        • new Date(timestampInMs)
        • new Date("October 13, 2014 11:13:00")
          • Not recommended as different browsers may parse the string differently
  • Methods
    • getTimezoneOffset(); // 300
    • toUTCString();
    • toTimeString();
    • All the methods below have their variants with set, getUTC and setUTC.
      • getFullYear(); // 2015
      • getMonth(); // 0
      • getDate(); // 1
      • getDay(); // 0
      • getHours(); // 0
      • getMinutes(); // 59
      • getSeconds(); // 33
      • getMilliseconds(); // 100
      • getTime(); // timestamp in milliseconds

Math

  • PI
  • SQRT2
  • SQRT1_2
  • power(number, exp)
  • sqrt(number)
  • round(9.12); // 9, 9.53 => 10
  • ceil(9.01); // 10
  • floor(10.99); //10
  • max(10, 2.1, 8.5, 19, 5.9); // 19
  • min(10. 2.1, 8.5, 19, 5.9); // 2.1
  • abs(-7); // 7
  • random()
    • returns a value from 0 to 1
  • sin(30)
  • cos(30)
  • tan(30)

JSON

Scopes

  • Everything by default is in global (window in case of browser) scope unless var keyword is used.
  • No block scope, say if block.
  • Scope resolutions starts from inner most block to global
  • Lexical Scope:
    • Children inherit scope data from their parents
    • Closures maintain references to the used variables

// this is also a good example of how a closure works function makeGreeter(greeting, punc) { punc = punc || "!!"; return function (sender) { return sender.trim() + ", " + greeting.trim() + punc.trim(); } var hello = makeGreeter("hello"); hello("John"); // John, hello!! // hello retains references to greeting and punc var howdy = makeGreeter("howdy", "??"); howdy("Jason"); // Jason, howdy?? // howdy maintains references to its own set of variables, different from hello() // set hello and howdy to null to free up memory

- When using a variable from outer scope(specially global) a number of times, assign that to a local variable to save resolution cost.
- Do not clutter global scopes, use immediately invoked functions instead.


## Functions
- Do not care about number of arguments
- Can't define default value in signature (unless using ECMAScript6 or above, most environments use ECMAScript5 today(June 2015))
  - one option would be to do
  ```javascript
  arg = arg || "defaultValue";

but this would fail for falsey values

  • safer bet is:
typeof a !== 'undefined' ? a : 42;

Using !== instead of != to prevent the coercion as 1 != true is false but 1 !== true is true

  • Functions themselves are objects and have methods of their own
  • Every function has access to two special objects
    • this. For global ones this is set to window.
      • bind(object) to get a copy of function bound to passed object
        • does not work in IE8, use polyfill.
      • call(object[, arg1, arg2, ...]) to call function on a specific object with explicit arguments
      • apply(object[, argumentsArray]) to call function on a specific object with an array of arguments Using any of the above 3 would change the meaning if this inside function.
    • arguments
      • looks like an array even though it is an object, might change in future versions
      • contains passed arguments even if function signature doesn't capture any
      • callee property returns a reference of the current function. Good for recursion
        • it is safer than calling the function by the name as the name could change.
  • Not many global functions, most functions are bound to some sort of object.
  • Immediately Invoked Function or IIF:
(function () {
    //code here
}());
  • Can use both, function declaration and function expressions
    • function declaration are moved to top of the execution so we can call them before we define them. Same is not true for function expressions.
  • Every call creates a new execution context. Make sure to set closure variables to null when not needed.

Error Handling

try {

} catch(err) {

} finally {

}

Polyfill

  • Check if a certain expected API is available, if not, provide with an implementation. Use to add missing features across different environment.
if (! String.prototype.trim) { String.prototype.trim = ...; }

Shim

  • Fix unique behavior of a platform to normalize same API across different platforms by intercepting calls to existing API. Used to deal with browser-specific behaviors or fix bugs.
  • Common example is trying to fix the unique behavior in IE

Promises

  • Used to achieve the same purpose as callbacks with more readable code, support for multiple async jobs and better error handling.
function isUserTooYoung(id) {
    return openDatabase(db)
        .then(getCollection)
        .then(find.bind(null, {'id': id}))
        .then(function(user) {
            return user.age < cutoffAge;
        });
}

vs

function isUserTooYoung(id, callback) {
    openDatabase(function(db) {
        getCollection(db, 'users', function(col) {
            find(col, {'id': id},function(result) {
                result.filter(function(user) {
                    callback(user.age < cutoffAge)
                }
            }
        }
    }
}
  • When then() invokes a function it passes on the last promise's resolved result to it. In the above example last then() gets the user object found by the 2nd last then().
  • then() can take two callbacks, first one to invoke on success of last promise and second one to invoke on failure
  • Error handling is much easier. Just add a .catch(function() {});
somethingAsync()
.then(somethingElseAsync)
.then(somethingElseElseAsync)
.catch(function(error) {
  console.log("Failed!", error);
})
.then(somethingDifferentAsync)
.done(finalAsync);
  • .catch() can be added anywhere.
  • .catch() is just a syntactical sugar for:
.then(undefined, function(error) {  
})
  • Fancy error handling:
asyncThing1().then(function() {
  return asyncThing2();
}).then(function() {
  return asyncThing3();
}).catch(function(err) {
  return asyncRecovery1();
}).then(function() {
  return asyncThing4();
}, function(err) {
  return asyncRecovery2();
}).catch(function(err) {
  console.log("Don't worry about it");
}).then(function() {
  console.log("All done!");
});
  • Difference between then() and done()
    • then() changes result to the return of the last promise, done() keeps it intact from the last call.
    promise.then(function (x) { // Suppose promise returns "abc"
     console.log(x);  //abc
     return 123;

}).then(function (x){ console.log(x); //123 }).then(function (x){ console.log(x); // undefined as the console.log in above then() didn't return anything })

vs
    ```javascript
    promise.done(function (x) { // Suppose promise returns "abc"
    console.log(x); //abc
    return 123;
}).done(function (x){
    console.log(x); //abc
}).done(function (x){
    console.log(x); //abc
})
  • Promises are resolved only once so caching is really easy for cases when we want to make single request even if there are multiple invocations.
var _cache = {};
function doSomethingCool(id) {
  if (! _cache[id]) {
    _cache[id] = thatSomethingCool();
  }
  return _cache[id];
}
 
doSomethingCool('123').then(...);
 // Following would not call thatSomethingCool() again, instead use the cached value 
doSomethingCool('123').then(...);
  • And about multiple async jobs
Promise.all([first(), second()]).then(function() {
  // all loaded
}, function() {
  // one or more failed
});

Timers

  • setTimeout(function, speed);
    • returns id and calls said function once after speed ms, does not block processing
  • clearTimeout(timeoutId);
    • cancels a queued Timeout call
  • setInterval(function, speed);
    • behaves same as setTimeout() except keeps calling the function over and over till interval is cleared.
  • clearInterval(intervalId)

Objects

  • Ways to create objects
// least common?
var person = new Object();
person.firstName = "John";
person.lastName = "Doe";
person.getFullName = function (separator) {
    separator = typeof separator !== 'undefined' ? separator :  " ";
    return this.firstName + separator + this.lastName;
};

// commonly used when we need to set a custom prototype for the object
// being created. Custom prototype can be passed as first argument to
// createObject here
var obj = Object.create();

// most common syntax
// equivalent to: Object.create(Object.prototype)
// Properties and methods can be added directly
// inside the literal notation or outside.
// Doing it inside the literal is preferred to save
// repeating the object variable name.
var person = {
    firstName : "John",
    lastName : "Doe",
    getFullName : function (separator) {
        separator = typeof separator !== 'undefined' ? separator :  " ";
        return this.firstName + separator + this.lastName;
    }
};


// constructor function:
// could also do: var Person =  function(firstName, lastName)
function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.getFullName = function (separator) {
        separator = typeof separator !== 'undefined' ? separator :  " ";
        return this.firstName + separator + this.lastName;
    };  
}
var person = new Person("John", "Doe");

// factory
function createPerson(firstName, lastName) {
  return {
    firstName : firstName,
    lastName : lastName,
    getFullName : function (separator) {
        separator = typeof separator !== 'undefined' ? separator :  " ";
        return this.firstName + separator + this.lastName;
    };
}
var person = createPerson("John", "Doe");
  • Any function can be a constructor function. Convention is to have the first letter as capital e.g function naming follows TitleCase
  • When instantiating an object inside constructor we can choose to also add methods to that object. BUT, this should be done only when where the function is not supposed to change. If we bundle functions inside the constructor there is some overhead in object creation as each time we would need to create a fresh copy of those functions.
  • Dot as well as array notation can be used to access object properties. Dot notation would fail if the property key is not a valid identifier, say it has spaces or it is a reserved keyword or starts with a number, ...
console.log(person.firstName);
console.log(person["lastName"]);
  • Each object has 2 things: key-value properties and a pointer to another object called prototype.
  • Object properties' data-descriptors can be set as:
    • writable
      • self explanatory. writable=false would result in readonly property.
    • enumerable
      • whether or not expose this property to the properties loop.
    • configurable
      • whether or not we allow redefinition of property with different data-descriptors
    • The short hand syntax above set all three to true.
    • Use Object.getOwnPropertyDescriptor(object, "property") to get descriptors of a property.
  • Objects can also have accessors (getter & setters).
var person = {};
// setting data descriptors
Object.defineProperty(person, 'firstName', {
  value: 10,
  writable: true,
};
// setting data descriptors
Object.defineProperty(person, 'lastName', {
  value: 10,
  writable: true,
};
// setting accessors for a dynamic/computed property
Object.defineProperty(person, 'fullName', {
  get: function() {
    return this.firstName + " " + this.lastName;
  }
};
  • Property definitions can also be combined in one block of code using defineProperties()
var person = {};
Object.defineProperties(person, {
  firstName : {
    value: 10,
    writable: true,
  },
  lastName : {
    value: 10,
    writable: true,
  },
  fullName : {
    get: function() {
      return this.firstName + " " + this.lastName;
    }
};
  • One might prefer to use functions for computed properties instead
var rectangle {
height: 10,
width: 20
};
Object.defineProperty(rectangle, 'area', {
  get: function() {
    return this.height * this.width;
  }
};

vs

var rectangle {
height: 10,
width: 20
area: function() {
    return this.height * this.width;
  }
};

Given the context both are valid. The first case might be used where we need it as a property instead of a function. Accessors really shine when we are dealing with boolean properties so instead of:

el.setEnabled();
el.setDisabled();
el.isEnabled();

we have

el.enabled = true;
el.enabled = false;
el.enabled

where enabled would be a dynamically computed property using set and get accessors on backend.

  • Enumerating Properties
for (var prop in obj)
{
  console.log(obj.prop);
}

or

for (var prop in Object.keys(obj))
{
  console.log(obj.prop);
}
  • General guidelines
    • Use literal notation when only one of a kind is needed
    • Prefer Constructor over factory
    • Attach methods to prototype instead of object itself
    • Use Object.defineProperties() and set proper flags, better if explicit, and do it outside constructor.

Inheritance

  • JS does not have classes. Everything is object.
  • Every function has prototype property that refers to an object that'll be used as prototype for the objects created through that function.
    • __proto__ is the actual object use for identifier resolution, while prototype is just available on functions and is used to initialized __proto__ for the objects created using that function

function Point(x, y) { this.x = x; this.y = y; } var myPoint = new Point(); // proto isn't part of the standard yet, do not use it on production // the following are all true myPoint.proto == Point.prototype myPoint.proto.proto == Object.prototype myPoint instanceof Point; myPoint instanceof Object;

- When calling a function on an object, local functions to that variable are consulted first ( ```hasOwnProperty('methodName')```) and then the functions on its prototype and then the functions on its prototype's prototype and so on till a null is found. 
- One of the difference between the locally bound functions inside constructor and the prototype one is that the prototype ones can be dynamically changed and the changes would apply to all objects (as objects store references, not the actual functions, to the functions on prototype)but the local ones are always part of the object itself.
- Prototype
  - Easiest way to understand prototype is to think of constructor function as class and the prototype as a set of shared members(data and methods)
  - ```Object.create(protoTypeObject)``` can be used to create a new object with custom prototype:
   ```javascript
(function () {
    'use strict';
    var Person = function (firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.localFunction = function () {
            return "localFunction";
        };
    };
    Object.defineProperties(Person.prototype, {
        "sharedProperty": {
            value: 10,
            configurable: true
        },

        "sharedPropertyThroughAccessor": {
            // we could have used value: here instead. Actually that is better because this isn't like a get/set
            // property. But, we have used get: here just to demonstrate that we can.
            get: function () {
                return "shared property through accessor";
            },
            configurable: true
        },

        "sharedMethodAsProperty": {
            value: function () {
                return "shared method as property";
            },
            configurable: true,
        }
    });
    Person.prototype.sharedMethod = function () {
        return "shared method";
    };
    var Employee = function (firstName, lastName, title) {
        Person.call(this, firstName, lastName);
        this.title = title;
        this.localFunction = function () {
            // localFunction can't be overridden the easy way
            // not using closure around (new Person()).localFunction because
            // then any changes we make to Person.localFunction() would not be
            // reflected here. May be we should use closure as Person's localFunction
            // is local afterall.
            return (new Person()).localFunction.call(this) + " overridden";
        };
    };
    Employee.prototype = Object.create(Person);
    var sharedProperty = Object.getOwnPropertyDescriptor(Person.prototype, "sharedProperty").value;
    Object.defineProperty(Employee.prototype, "sharedProperty", {
        value: 11 + sharedProperty,
        configurable: true
    });
    var sharedPropertyThroughAccessor = Object.getOwnPropertyDescriptor(Person.prototype, "sharedPropertyThroughAccessor");
    // bind with Employee, else you'd get person1's properties
    var sharedFn = sharedPropertyThroughAccessor.get.bind(this);
    Object.defineProperty(Employee.prototype, "sharedPropertyThroughAccessor", {
        get: function () {
            return sharedFn() + " overridden";
        }
    });
    var sharedMethodAsProperty = Object.getOwnPropertyDescriptor(Person.prototype, "sharedMethodAsProperty");
    var sharedMethodAsPropertyFn = sharedMethodAsProperty.value.bind(this);
    Object.defineProperty(Employee.prototype, "sharedMethodAsProperty", {
        value: function () {
            return sharedMethodAsPropertyFn() + " overridden";
        }
    });
    var sharedMethodFn = Person.prototype.sharedMethod.bind(this);
    Employee.prototype.sharedMethod = function () {
        return sharedMethodFn() + " overridden";
    };

    var johnDoe = new Employee("John", "Doe", "Principal");
    // this would log "localFunction overridden"
    console.log(johnDoe.localFunction());
    // this will log "21"
    console.log(johnDoe.sharedProperty);
    // this will log "shared property through accessor overriden"
    console.log(johnDoe.sharedPropertyThroughAccessor);
    // this will log "shared method overridden"
    console.log(johnDoe.sharedMethod());
    // this will log "shared method as property overridden"
    console.log(johnDoe.sharedMethodAsProperty());
}());
  • isPrototypeOf()
  • getPrototypeOf()

Namespaces

  • No notion of namespaces
  • Best we can do is create a cryptic object name and wrap everything in it
var cryptNamespace = (function() {
// code
} ());
  • Problem: what if cryptNamespace already exists due to some other version or a copy of script?
var cryptNamespace = (function(cryptNamespace) {
// code
return cryptNamespace;
} (cryptNamespace || {}));

Browser Specific

Window, DOM

  • window is implied for global identifiers
  • three dialog boxes
    • alert("message")
    • confirm("message");
      • returns boolean
    • prompt("question", "defaultValue");
      • returns supplied value
  • location
    • set and get operations are same for location or location.href
  • encodeURIComponents(value)
  • dom is slow so get elements ready before manipulating dom e.g. create element, set attributes, append/replace...
  • document Methods:
    • getElementsByTagName("tagName")
      • returns NodeList, not Array, objects are live, changes are applied directly to page, new objects appear automatically
    • getElementById("id");
      • returns object
    • getElementByClassName("class");
      • returns objects
    • querySelector("div p");
      • returns the first match, #id (getElementById() is faster for just ids)
    • querySelectorAll("p");
      • returns the all matches in a NodeList, not live.
    • createElement("tagName");
      • returns an element, just object, still not append to page anywhere
    • createTextNode("text");
      • does not regard html
  • document Object properties and methods
    • parentNode
    • tagName
    • innerHtml
    • className
      • could assign multiple classnames separated by space.
      • Wrap class names in spaces to ensure they are not concatenated to existing/future classnames, would also made replacing/removing an existing class name really easy.
      • An alternate would be classList
    • style
      • camelCase properties that have a hyphen, doesn't retrieve style attributes from css, would have to use computed styles for that
    • currentStyle
      • accessing style in legacy IE versions
    • offsetLeft
    • offsetRight
    • offsetTop
    • offsetBottom
    • appendChild(element)
    • insertBefore(newElement, elementOnPage)
    • replaceChild(newElement, elementOnPage)
    • setAttribute("property", "value");
      • a lot of attributes are available directly as property, id, cssClass
    • classList
    • getComputedStyle(elementObject, null);
      • 2nd argument is pseudo element match that not every browser supports,.
      • Returns a CSSStyleDeclaration object, use getPropertyValue("styleKey") to get value for specific style.

Events

  • DOM Level0 Event Handles:
    • oneventNameHere = function () {}; // e.g. onclick, onload, etc
    • Every browser supports them
    • Can only bind one handler at a time
  • Standard
    • addEventListener("eventNameHere", handler, capture = true);
      • Older browsers needed all three arguments.
        • Last argument is if we want to use capture(document -> body -> .. -> target) or bubble(target -> ... -> body -> document).
        • W3C standardized by merging them e.g. capture -> target -> bubble.
        • Recommended to use false to use bubbling as IE8 low do not support capturing.
      • A single parameter is passed to handler e.g. event.
        • event has useful properties like type and target, mostly used for event delegation though. Oh and our favorite preventDefault() too.
    • removeEventListener("eventNameHere", handler, capture = true);
      • Needs exact same params to remove any handler as when we added listener for it.
      • Declaring same anonymous function won't work as each function declaration is a new object.
  • Legacy IE (IE8 and below)
    • attachEvent("onEventNameHere", handler);
      • No third argument as IE8 and below only support bubbling
      • global event object is created for every event which gets created with type, srcElement and other data about the event.
      • event.returnValue = false instead of event.preventDefault()
    • detachEvent("onEventNameHere", handler);

Keyboard Events

  • keydown | keyup
    • event.keyCode; // works in all browsers, case insensitive so assumed all keys to be caps
    • event.altKey, event.ctrlKey, event.shiftKey
  • keypress (does not happen for modifier keys)
    • standard browsers: event.charCode; // ascii code of the key pressed
    • legacy IE: event.keyCode; // ascii code of key presed

Event Delegation

  • Compromise event trigger performance for event binding performance.
    • Event Delegation when done badly could also cause unexpected events being triggered from newly added elements even though we didn't bind any events to them yet.
    • It could also lead to if-else-if-else-if-else-if-else-if-else-if-else-if-else-if-else inside the handler.
    • WITH GREAT POWER COME GREAT RESPONSIBILITIES.
  • Use bubbling
  • Attach event to a wider scope, get the event target and then based on target behave differently

Forms and Input Elements

  • Forms
    • elements
    • submit()
      • does not trigger submit event.
    • ``reset()```
  • Input Elements
    • value
    • type
    • disabled
    • focus()
  • Text Elements
    • select()
  • Select Lists
    • remove(index)
    • Adding a new option

var opt = new Options("Text", "value"); // following would add opt before the current 2nd entry in the list select.add(opt, select.options[2]);

  - Finding selected option
    - Old Style
      - ```selectedIndex```
      - ```options```
    - Future
      - ```selectedOptions```
- Checkboxes/Radio Buttons
  - ```checked```


## AJAX
- ```XMLHttpRequest```
  - would not work on IE though :P
- ```onreadystatechange = function () {}```
- ```readyState; // state notifications for async, 4 == ready```
- ```status; // http response status code, ok = [200-299,304] ```
- ```open("REQUEST_METHOD", "URL", async = true)```
- ```setRequestHeader("HeaderName", "HeaderValue");```
  - Common use case is to set ```Content-Type``` header to ```application/x-www-form-urlencoded``` or ```application/json``` etc
- ```send(postData = null)```
- ```responseText```
- ```responseXML; // would contain xml object if response was xml```


## Local Storage
- **NOT** cookies
- Data stored is local to the domain that set it
- Not supported in IE7
- key-value store
- Values are always stored as string.
- Use JSON to store objects. 
- ```localStorage```
  - Global object available on window
  - Methods
    - ```setItem("key", "value");```
      - could also set it as a direct property
    - ```getItem("key");```
      - could also access it as a direct property
    - ```removeItem("key");```
    - ```clear()```



# Misc
- 
```javascript
var globalGetFullName = function (separator) {
        separator = typeof separator !== 'undefined' ? separator :  " ";
        return this.firstName + separator + this.lastName;
    };  
function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.getFullName = globalGetFullName;
}
// a is the actual function, a is a copy of constructor and can be used to construct objects
var a = Person;
// b is undefined, not using new
var b = Person();
// c is same as b, except that now we have function in place, c is also undefined
var c = (function (firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.getFullName = globalGetFullName;  
}());
// d is  new person object with undefined as both properties
var d = new Person();
// e if a new person object with both properties set correctly
var e = new Person("Jane", "K");


// factory
function createPerson(firstName, lastName) {
  return {
    firstName : firstName,
    lastName : lastName,
    getFullName : globalGetFullName
  };
}
// l is a copy of factory and it can be create to construct objects
var l = createPerson;
// m is a option with both properties set to undefined
var m = createPerson();
// n is same as n, except function is executed in place, n is also undefined.
var n =  (function createPerson(firstName, lastName) {
  return {
    firstName : firstName,
    lastName : lastName,
    getFullName : globalGetFullName
  };
}());
// o is an object(a copy of actual object created by factory?) with both properties set. 
var o = new createPerson("first", "last");
  • node wraps all code files in iif
  • Use nodemon to simulate live-reload in node
  • Most callbacks in node take a callback with request and response object, in that order.

Next

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment