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, function
dynamic size
typeof
returns string.
Array
can 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]); }
. Usebreak
to 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 _.select
join to string:
arr.join
reduce 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 + cur
in 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 _.every
Test some:
arr.some
or_.some or _.any
Find first, else return
undefined
:array.find or array.findIndex
Includes:
(ES7):
arr.includes or _.contains
indexOf 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:
Infinity
and-Infinity
NaN
any 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; // 56
hex number:
var hexNum = 0xA2 or 0xf1
Convert anything to number:
Number()
Number(null) === 0
Number(undefined) === NaN
Number('') === 0
Number('a') === NaN
Number('0x1') === 1
parseInt
parseInt
parses until found invalid character, + simply convert the string to int/float and it returns NaN if there is ANY invalid character.parseInt(' 1') === 1
parseInt('') === NaN
returns NaN if cannot convertparseInt(' 123abc4') === 123
always use radix:
parseInt('09', 10)
Otherwise '09' will be treated as hex and result as 0
paserFloat
It always convert to oct. If starts with 0x, it returns 0.
Get digits:
String(321)split('')
Check if it's integer:
Number.isInteger
polyfill 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
u1235
is unicode nnnncharAt(index), indexOf
match(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 0substring
will 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
toString
orString()
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
undefined
If 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 isnull
orundefined
, 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 true
Strict Equality Operator
===
: doesn't not perform type coercion recommended'' == false // return false
when comparison includes reference type, the comparison (both == and ===) performs pointer comparison.
{} != {}
Global Objects / Methods
Set: unique values of any type,
has
Map: dictionary, any type can be key,
size
,get/set
Methods:
isNaN, etc
let 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.print
display 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-9
Use 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.prototype
are all nonenumerable. Ex,toString
is in prototype but it's not enumerable'toString' in {} // -> true
use
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
in
operator 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 [] === 'object
BUT
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 .. in
works 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
).arguments
is 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.length
required params lengthFunction.prototype.bind(thisArgs, arg1, arg2...)
creates a new function that bindsthis
and currying parameters.so 'this' is always 'thisArgs'
use when in
setTimeout
callback 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.
var
is limited in the scope.the scope implicitly defines a reference to
this
ES6: block scope
let
is 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
. Sothis
refers 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:
var
creates 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.let
creates 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?
var
only the declaration part
and it'll be initialized as
undefined
function declaration:
function foo() {}
let const
only 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,
this
is bind to 'Call-site', the invoking object.In arrow function,
this
is bind to the context 'Where is defined'. If no parent defines scope, then the context iswindow
You can use
bind
to changethis
manually.in event handler,
this
is 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
,this
is set to a fixed value when it's defined. Or useapply
orcall
to dynamically change context.Arrow function doesn't bind
this
,arguments
.Arrow function
this
is 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
this
in 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 Constructor
Assertion
i18n
navigator.languages
returns the user's preferred languages//["en-US", "zh-CN", "ja-JP"]
navigator.language
is 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