Type coercion: a set of rules that often aren’t what you want or expect. This is called type coercion.
- ==,!= (equal to, true: "5"==5 ) (string comparison: differ from Java)
- ===, !== (equal value and equal type, false: "5"===5 )
- > (true:"9">"19", false: "9">19)
- && || !
- since coercion converts null/undefined to false
- and || and && return value depending on value on their left, return either original left or right value
- || : return left or if empty/null then right
- && : return right if left true, or left (thng1 "and then" thing2)
- also: right value evaluated only when necessary
- typeof
- instanceof - whether an object was derived from a specific constructor
- property_name in some_object - test if object has a property of that name
- bitwise operators
- in - check name among enumerable properties
- true? 1:2
- eval - execute string in current scope (generally bad idea)
- ` (back-tick, grave accent) - template literals
- place holders ${expression}
- `\`` === '`' // -> true, escape back tick
- newline part of literal - multi-line template ok
- nesting allowed since ES2015 `.... ${... `..${...}..`}`
- inside place holders, its parsed to a function, by default concatenates the parts into a single string
- tagged template:
- tag: function myTag(strings, exp1, exp2){...};
- template ... myTag`.... ${exp1} ... ${exp2}`
- it does not need to return a string, can be anything
- String.raw`anything without escape`
See separate page
- .trim
- .charAt
- .match(/regular expression/)
- .replace(/regular exp/, "something")
- .replace(/([\w ]+), ([\w ]+)/g, "$2 $1")); // refer back to matched group
- .replace(..., function(matched_groups)) // replace with a mapping function
- var s = "the cia and fbi"; console.log(s.replace(/\b(fbi|cia)\b/g, function(str) { return str.toUpperCase(); })); // → the CIA and FBI
- indexOf (non-regexp) / search (regexp)
Array
- [ ]
- .push - add to end / .pop - remove at end and return, change length
- .unshift / .shift - adding / removing array at start, change length
- .join - glue all member to a single string with argument as in-between
- typeof [] === "object"
- dynamic length, length is the maximum index + 1
- delete operation does not change length
- .indexOf / .lastIndexOf, searching a given element, parameters (something_to_be_searched, optional_where_to_start_from)
- .slice - takes an inclusive start and exclusive end, return a slice
- another use of the prototype function, to convert a collection to a real array (see example)
- + : glue two arrays
- filter(function_return_boolean)
var arrayish = {0: " one ", 1: " two " , length : 2};
var real = Array . prototype . slice . call ( arrayish , 0) ;
real . forEach ( function ( elt ) { console . log ( elt ); }) ;
// → one
//
two
Object
- { }
- {}.property_does_not_exist === undefined - true
- delete x.unwanted_property - remove that property
- Object.create - create object with specific prototype
- "property_name" in someObject - test if a property exists
- for (var propertyName in Object) - loop through properties
- Object.(dot)
Properties
- somthing.property / something["property"]
- Object.keys(something) - array of property names (enumerable properties only)
- Object.getOwnPropertyNames(something) - both enumerable / non-enumerable properties
- for (var name in some_object) - loop through names of enumerable properties
- in - test property existance
- array.length - get number of elements
- try to attach property to non-object values - will return with no complain but the value does not attach, how bad Javascript is!!!
- enumerable / non-enumerable
- by default enumerable
- standard properties in Object.prototype etc. non-enumberable
- Object.defineProperty(object_to_attach, name_as_string, {enumerable:false, value: some_value});
- something.hasOwnProperty(name_as_string) -> check if the thing itself has a property (often more useful than "in")
- for (var name in something) { if (something.hasOwnProperty(name)) { // ... this is an own property } }
- value property or getter/setter
- getter setter - adaptable but cause lots of boilerplate codes
- get name_of_property() {return ....};
- set name_of_property() {... };
- Object.defineProperty(TextCell.prototype, "heightProp", { get: function() { return this.text.length; }
> Object.keys(Function.prototype)
[]
> Object.getOwnPropertyNames(Function.prototype)
[ 'length',
'name',
'arguments',
'caller',
'constructor',
'apply',
'bind',
'call',
'toString' ]
>
Useful Objects
- Math - Math.max, .min, .sqrt etc
Method
- simply properties that hold function values
- some_object.some_method(x,y,z) -> some_method(x,y,z) where "this" set to some_object
- otherwise for non-method call, "this" set to global
Decorator (ES2015+, may require transpiler support, still not standardized yet, still at draft stage)
Makes easy to use decorator design pattern. Support classes and class members (properties, methods, getter/setters). For typescript, see https://www.typescriptlang.org/docs/handbook/decorators.html
@log()
@immutable()
class Example {
@time('demo')
doSomething() {
//
}
}
Class member decorator example:
function readonly(target, name, descriptor) {
descriptor.writable = false; // descriptor is class descriptor
return descriptor;
}
- Object.getPrototypeOf(some_object)
- is NOT some_object.prototype (if any)
- when search for a property that is missing in the object, it's prototype, then prototype's prototype, etc. will be searched
- the prototype of
- empty object - Object.prototype (root of tree-shaped prototype relations)
- console.log(Object.getPrototypeOf({}) == Object.prototype); // → true
- console.log(Object.getPrototypeOf(Object.prototype)); // → null
- functions -> Function.prototype
- array -> Array.prototype
- string -> String.prototype
- Object.create(the_prototype) - create an object with a specific prototype
- null allowed - a simple map
- ConstructorFunction (example name)
- new ConstructorFunction() - call function as a constructor, "this" bound to a fresh object, and is returned unless explicitly return another object
- ConstructorFunction.prototype (in fact all functions)
- DO NOT confuse ConstructorFunction.prototype with Object.getPrototypeOf(ConstructorFunction)
- ConstructorFunction.prototype
- is a property of the constructor named "prototype"
- is NOT the prototype of the ConstructorFunction
- is the default prototype of the instances of the ConstructorFunction
- therefore affects the behaviors of the instances of the ConstructorFunction not the function
- f.prototype === Function.prototype // -> false
- by default a plain empty object derives from Object.prototype
- Object.getPrototypeOf(ConstructorFunction)
- is prototype of the function
- Object.getPrototypeOf(f)===Function.prototype // -> true
- affects the behavior of the function (apply, bind, call etc.)
- the returned object is said to be an instance of the constructor
- will have ConstructorFunction.prototype has the instance's prototype
- do something to the ConstructorFunction.prototype to change all instances' behavior
- add method: ConstructorFunction.prototype.method_name = function(argument){...};
- instanceof - whether an object was derived from a specific constructor
- new RTextCell("A") instanceof RTextCell; // → true
- new RTextCell("A") instanceof TextCell; // → true
- new TextCell("A") instanceof RTextCell; // → false
- [1] instanceof Array; // → true
- almost every object is an instance of Object
- Override
- property of object overrides same name property of object's prototype
- Inheritance (not to be abused, "composition over inheritance")
// Inheritance
function RTextCell(text) { // constructor of a child type
TextCell.call(this, text); } // first allow parent constructor handle "this"
RTextCell.prototype = Object.create(TextCell.prototype); // set instances' prototype to an empty object based on parent's prototype
RTextCell.prototype.draw = function(width, height) { // define additional methods
- operate on other functions (as argument or return type)
- create new function
- change function (decoration)
- map, filter, forEach
- function
- some_aray.filter(function_of_member_return_true_false(member){}) - build new array with filtered elements
- some_array.map(function_convert_member(member){}) - build new array with mapped element
- some_array.forEach - do something for each member (side effect)
- the function as argument
- receives 1st argument as the element
- receives 2nd argument as index of the element
- some_array.reduce (reduce is sometimes called fold) - combine all elements into single value
- combine: function combines two members and return a combination (can do sum, combine, max/min, etc.)
- start: optional, the starting value (think of a member before the first)
- ["a","b","c"].reduce(function(x,y){return x+y},"?"); -> "?abc"
- function(x,y).bind(value_of_this, value_x) => function_bind_x_to_value_x(only_need_y) where "this" is bind the first
JSON.stringify and JSON.parse
Create
- new RegExp("abc", optional_options_such_as_gi)
- /abc/
Use
- .test - match or not
- .exec - match and return null or match object (or some_string.match(/abc/))
- new Date - current date and time
- new Date(ms_since_epoch)
- Date.now() - get ms since epoch of now
- new Date(year, month, day) / new Date(year, month, day, hour, minute, second, micro-second)
- month start from 0 (so 11 -> DEC)
- day start from 1
- getTime - ms since epoch
Error Handling
- Syntactic error - report immediately
- Others - run time
- throw new Error(some_description)
- can throw anything but Error has the stack dump
- try / catch
- try {...} catch (error) { ... } finally {... // run no matter what happens...}
- catch all or catch none, so be careful to check what you actually caught
- so check what was actually caught
- may define a customize error (see below) and check (instanceof)
- Strict mode
- "use strict" at the top
- just a little bit more strict
- "this" in functions but not called as methods -> undefined (strict mode); -> global scope (non-strict)
- Debugging
- "debugger" statement - pause if tool active (browser)
function CustomError(message) { this.message = message; this.stack = (new Error()).stack; }
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.name = "
CustomError";