JavaScript
JavaScript = ECMAScript + DOM (window.document) + BOM (window.document, window.navigator, window.location, window.history, window.screen, etc)
Good Tutorials
Type
JavaScript Types = Primitive types + Reference Type
Primitive type
null, undefined, boolean, number, string, symbol (ES6)immutable, fixed size memory
Reference Type
Object, array, functiondynamic size
typeof returns string.
Array
var a = Array(4); // array length of 4, but elements are all undefined
var a = Array('4'); // returns [4]
var a = Array()
var a = Array('a', 'b');
var a = ['a', 'b']
let arr = Array.from($('a')); // create from nodelistcan change length, like C# list:
a.push('c')can hold different data type
the length of the array is one more than the highest index. it's not always counting how many members in the array!
If you query a non-existent array index, you get
undefined
Callback is usually: element, index, array while element is required
Value Most of the operations will mutate the array.
copy itself to itself, [start, end) not including the endIndex:
copyWithin(targetIndex, startIndex, endIndex)Reverse:
Array.prototype.reverse()Sort:
arr.sort()if no function is provided, element is converted to string to sort, so
[10, 5].sort() is still [10, 5]sort numbers:
arr.sort((a, b) => a - b);
head:
shift()+unshift()tail:
pop()+push()Fill with value, [start, end)
arr.fill*Remove and insert in the middle (when deleteCount is 0):
arr.splice(start, deleteCount[, insert args]), it will return the removedclear content
arr.length = 0;orarr.splice(0, arr.length);
immutable operation:
Concat
return new array:
arr.concat(arr2)has flatten effect:
[1].concat(2, [3,4]) -> [1,2,3,4]
We could make it mutating too: in place (append b to a):
Array.prototype.push.apply(a,b)
Slice, return shallow copy [start, end):
arr.slice
Iterate
for:
for(let i = 0, l = list.length; i < l; i++) {console.log(list[i]); }. Usebreakto break out.for in
values():for (let elem in arr.values())arr.forEach: cannot break unless throw an exception
Transform
filter:
array.filter or _.filter or _.selectjoin to string:
arr.joinreduce and reduceRight(from end):
arr.reduce(callback, initial) # call back is (accumulator, currentValue, index, array)=> {})if no initial value given, first call, previousValue is arr[0] and currentValue is arr[1]
the callback function returns value that'll pass to next accumulator. There is no need to assign
acc = acc + curin the callback function.
Query/Test
Check if it's array:
Array.isArray()polyfill:
return Object.prototype.toString.call(arg) === '[object Array]';
Test all:
arr.every((element) => true)or_.all or _.everyTest some:
arr.someor_.some or _.anyFind first, else return
undefined:array.find or array.findIndexIncludes:
(ES7):
arr.includes or _.containsindexOf or lastIndexOf
Tips:
create array:
ES6:
Array(length).fill().map((_,i)=>i+1)ES6:
Array.from({length: 10}, (v, i) => i);Lodash:
_.fill(Array(10), 1);
Number
Special Numbers:
Infinityand-InfinityNaNany operation with NaN will rerturn Nan
NaN doesn't equal to anything, including itself
Hex and Octal:
If number starts with 0 and is a valid octal number, it'll be a octal number:
var octalNum = 070; // 56hex number:
var hexNum = 0xA2 or 0xf1
Convert anything to number:
Number()Number(null) === 0Number(undefined) === NaNNumber('') === 0Number('a') === NaNNumber('0x1') === 1
parseIntparseIntparses until found invalid character, + simply convert the string to int/float and it returns NaN if there is ANY invalid character.parseInt(' 1') === 1parseInt('') === NaNreturns NaN if cannot convertparseInt(' 123abc4') === 123
always use radix:
parseInt('09', 10)Otherwise '09' will be treated as hex and result as 0
paserFloatIt always convert to oct. If starts with 0x, it returns 0.
Get digits:
String(321)split('')Check if it's integer:
Number.isIntegerpolyfill on MDN
Tips: Random number
Math.random()-> [0, 1)
Tips: format number
link: https://codesandbox.io/s/js-tips-format-number-frd6v
String
string is value tpye.
It's unicode of 16bit
u1235is unicode nnnncharAt(index), indexOfmatch(regex)returns matchesNOTE if regex has /g: 1. it'll return first match; 2. you can match multiple times. See http://www.2ality.com/2013/08/regexp-g.html
replace(regex/g, 'to replace')specials '$1', etc.substr(index, length) vs substring(index, endIndex)not including endIndex`if negative number:
slice(index)index will become index+length:'abc'.slice(-1) -> 'abc'.slice(2) -> 'c'substr(index, length)index becomes index+length; length will become 0substringwill treat negative as 0
Can mix different type using '+' since JavaScript is weak typed. The non-string type is auto converted to string.
So, if you add a string to a number (or other value) everything is converted in to a string first
To convert to string, use either
toStringorString()String(null) === 'null'String(undefined) === 'undefined'
In place sort string with numbers:
'8902'.split('').sort().join('')Use
String.prototype.localeCompare()for string comparison in sort. Return negative number if it's before. You can also use'A' > 'a'
Special reference type: String, Boolean, Number
it's created on the fly then get destroyed.
Date
Only using new will return the object; Others will return the number or string.
new Date()new Date(2005, 0, 3)local time; year and month is required, month is 0 basedDate.UTC(2005, 0, 3)UTC time; Return number; year and month is required, month is 0 basedUse moment.js
Boolean
Sometimes you'll need to check boolean, it's better to force converting to boolean by:
null undefined
Special objects: null and undefined
null: a pointer to nothing (that's whytypeof null === 'object'. Most case it can be replaced byundefined;undefined: it's like null in other program.If you access a.name and a is {} then it returns
undefinedIf arr[out_of_bound_index], it returns
undefined
boolean: any value can be converted to boolean
Check is null or empty:
_.isEmpty():
check the length of array or string
CANNOT check number: _.isEmpty(10) === true
check if object has enumerable own-properties
Check null:
use
typeof instance.currentPosition !== 'undefined'Why not using
instance.currentPosition === undefined? it can throw errorCoffeeScript:
coffeescript: ? or ?. (the latter can soak up so a.address?.zip returns undefined instead of typeerror)
CoffeeScript's existential operator
?returns true unless a variable isnullorundefined, which makes it analogous to Ruby's nil?
Comparison
Equality operator
==: doesn't compare type, i.e, it converts the type first (performs type coercion) then compare"" == false // returns trueStrict Equality Operator
===: doesn't not perform type coercion recommended'' == false // return falsewhen comparison includes reference type, the comparison (both == and ===) performs pointer comparison.
{} != {}
Global Objects / Methods
Set: unique values of any type,
hasMap: dictionary, any type can be key,
size,get/set
Methods:
isNaN, etclet id = setTimeout(()=>console.log('future'), 1000),clearTimeout(id)let id = setInterval(()=>console.log('again'), 1000),clearInterval(id)Use setTimout to emulate interval, as timeout is pushed to the queue, where interval might run in overlap.window.printdisplay print windowlocation: window.location is the same as document.locationencodeURI
replaces all characters except:
; , / ? : @ & = + $ - _ . ! ~ * ' ( ) # a-z 0-9
encodeURIComponent
replaces all characters except
- _ . ! ~ * ' ( ) a-z 0-9Use it to encode the value part: because it'll encode
=and&so it's not supposed to encode the whole param stringencodeURIComponent("var1=value1&var2=value2").
Object
the property name will always be string, even you created like this
{a:'b'}Use dot notation when accessing properties
Use subscript notation [] when accessing properties with a variable.
for (let prop in obj)will iterate all enumerable props (including the prototype ones) in arbitrar orderAll properties that we create by simply assigning to them are enumerable.
The standard properties in
Object.prototypeare all nonenumerable. Ex,toStringis in prototype but it's not enumerable'toString' in {} // -> trueuse
hasOwnProperty(key)to check if it's in instance
for (let value of arr)(ES6). It's using iterator (next: ()=> {value: x, done: false})The
inoperator check if the specified property is in the specified object.use
hasOwnProperty(key)to check if it's in instance```js
let obj = {
a: 'a'
};
console.log('a' in obj); // true
obj.a = undefined; console.log('a' in obj); // true
delete obj.a; console.log('a' in obj); // false
```
typeof, check if it's a basic type plus others, it only returns those string: 'undefined', 'null', 'boolean', 'string', 'number', 'object', 'symbol', 'function'so
typeof [] === 'objectBUT
typeof null === 'object';See MDN explanationusage: check method defined in prototype:
if (typeof this.sayName !== 'function')
a instanceof Constructor, check if it's a reference typeUse constructor, not string: so
[] instanceof Object, not 'object'
(TODO) Check if an object is a type
Why not
instanceof?Why not
typeof? Because typeof returns only those 5 types, and array is Object type. For example,typeof [] === 'object', you cannot tell if it's array. See here
object detection, check if it has property or method
JSON.stringify(obj, ['fliter', 'list])can filterCustom getter setter:
FP operations
Freeze:
const frozen = Object.freeze(obj)Create shallow copy:
Prototype
Constructor
A constructor is just a function called with new.
What happens?
create new object
this bound to new object
call the constructor function
return the object
Prototype Chain
every instance created with the same constructor will share the same prototype: object derived from Object.prototype.
How to create prototype-less object? (so that
for .. inworks without check)
Example
Prototype chain:
call parent constructor
set prototype to parent prototype
ES6, it's just syntax sugar, remains prototype based.
Function
arguments
Always has
arguments(note it's notthis.arguments).argumentsis a build-in object, it's array like.To convert it to array:
Array.from(arguments)const a = [...arguments];Array.prototype.slice.call(arguments)
Because of 'arguments', there is no function overloading.
function.lengthrequired params lengthFunction.prototype.bind(thisArgs, arg1, arg2...)creates a new function that bindsthisand currying parameters.so 'this' is always 'thisArgs'
use when in
setTimeoutcallback to refer this, that's also why=>in ES6 don't need to bind anymore
Funnction.prototype.apply(scope, paramsArray)andFunction.prototype.call(scope, param1, param2, etc)apply uses array
call uses comma
Math.max.apply(null, [1,10,-1])
Assignment makes a copy of the value only if it's a primitive type (like Number, Boolean, String, etc...). Otherwise, assignment just copies a reference to the same object (Object, Array, etc...). A new object is not created with assignment.
Arguments are always copied by value. Even if the type is reference.
Return value
Function output: funciton always return a value. If no return statement or
return;, it returnsundefined.
Declaration vs Expression
Declaration (will be hoisted)
Expression:
IIFE: immediately-invoked function expression
Why? It's useful when you have some work to do, some initialization maybe. You need to do it only once and you don't want to leave any globals lying around after the work is finished.
How? It's used to avoid hoisting and creating scope. A function creates a scope.
Function Name
Why you can pass function name to map function?
Actually you’re NOT omitting function parenthesis, what you mean here is passing the function reference so that the map knows which function to call. See http://stackoverflow.com/questions/5520155/settimeout-callback-argument/5520190#5520190
Closure
Closure: when the inner function makes reference to a variable to the outer/surrounding function, this is called closure.
More formal definition: A closure = a function + lexical environment within which that function was declared.
Usage: promise chain, currying function, this-that pattern,'private' data in module or function (because function creates scope)
Common error when creating closure in loop:
Scope
Who can create scope?
function scope: created by funciton.
varis limited in the scope.the scope implicitly defines a reference to
this
ES6: block scope
letis local to the block scope, not the function scope.the scope does not implicitly defines a reference to
this
ES6: lambda scope
the scope does not implicitly defines a reference to
this. Sothisrefers to enclosing scope.
Declared variable is a property of the scope. Undeclared variable too. So, both var a = 10; b = 11; is accessible in global window.
for loop:
varcreates one binding as well as a variable (and the declaration part will be hoisted), so when i is accessed in a callback function, it always refered to the final i value.letcreates binding each iteration so it works normally
How does js lookup variable?
Similar to stack, look for local then global. Local variables 'shallow' the global ones.
If there is a local same name identifier, the search will stop.
Examples:
Hoisted
What will be hoisted?
varonly the declaration part
and it'll be initialized as
undefined
function declaration:
function foo() {}let constonly the delcaration part
it will be uninitialized, trying to use it will cause 'Reference error: y is not defined'.
This is temporal dead zone (anything above the actual statement). See: https://stackoverflow.com/a/31222689
this
Rules:
Normally,
thisis bind to 'Call-site', the invoking object.In arrow function,
thisis bind to the context 'Where is defined'. If no parent defines scope, then the context iswindowYou can use
bindto changethismanually.in event handler,
thisis bind to invoking target. (NOTE if you define event handler using arrow function then it's bind to window)
Examples:
Normally, 'this' is the invoking object. If no invoking object, is the global object. (window or global in Node).
When using
bind,thisis set to a fixed value when it's defined. Or useapplyorcallto dynamically change context.Arrow function doesn't bind
this,arguments.Arrow function
thisis determined by where is defined. And it refers to the enclosing execution context. You can think it's using the this-that pattern. (Can use babel to verify) 箭头函数从封闭它的(函数或全局)作用域采用 this 绑定.Arrow function is not suitable to define methods:
So arrow function cannot be used as constructor, because there is no
thisin it.Default binding. It means binding loss: it happens whenever you’re accessing a method through a reference instead of directly through its owner object.
Why? Because the invoking site is window.
So it also means, when you pass function as callback (which implicitly do the assignment in local scope, and when invoking, none is invoking it.), it's window.
How to fix? this-that pattern or arrow function.
Reference:
Error Exception
catch: there is no selective catch.
catch(e)You can create your own error and use
instanceOf ConstructorAssertion
i18n
navigator.languagesreturns the user's preferred languages//["en-US", "zh-CN", "ja-JP"]navigator.languageis the first element of the above returned array
How to test?
Use chrome://settings/languages#lang and (important) make sure that the language you selected is the top choice (the preferred language). The navigator value will change accordingly
Pattern
default value if it doesn't exist
Use ES6 default parameter instead. Previously: Use || NOTE this pattern doesn't work if the value is ''.
Console & Debug
debugger;
If the result is 0, the elements are not in the DOM: console.log($(".theElements").length);
_ Debug JQuery: http://fixingthesejquery.com/#slide23
How to open a new window without being blocked?
If the window is not a user click resullt, it'll be blocked.
Reference:
How to read binary file from the browser?
Last updated