- Primitive Types: string, number, boolean, undefined, null, symbol.
- Non-Primitive(Object) Types: array, object, function, date, regx.
- JSON is basically an object represented in the form of a string.
// Parse JSON to object by JSON.parse()
let obj = '{"gretting": "hello"}';
let plainObj = JSON.parse(obj);
console.log(plainObj); // {gretting: 'hello'}
// Parse object to JSON by JSON.stringfy()
let data = {"name": "Erika"};
let jsonData = JSON.stringfy(data);
console.log(jsonData); // '{"name": "Erika"}'
Not Defined
- Not defined means the variable doesn't exist.
Undefined
- Undefined means a variable has been declared but has not yet been assigned a value.
- Type of undefined = undefined.
let a;
console.log(a); // undefined
console.log(typeof a); // undefined
Empty
- Empty is used to refer to a unique string with zero length.
let a = "";
console.log(a); // ''
console.log(a.length); // 0
let b = " ";
console.log(b); // ' '
console.log(b.length); // 1
Null
- Null is used to refer to nothing.
- Type of null = object.
let a = null;
console.log(a); // null
console.log(typeof a); // object
console.log(null == undefined); // true
console.log(null === undefined); // false
- Related Reference: Javascript 中 undefined 和 null 的差異, JavaScript 中 undefined 和 null 的區別是什麼
Call By Value
- When you declare a
primitive type (string, number, boolean, null, undefined, symbol) variable
a and b, it will has own memory location and store it's own value in it, then assign b equal to a, b alsohas own memory location
and store a's value in it. b's valuewill not change
when a's value changes, a and b's memory location is isolate, they won't interrupt each other.
var a = 2;
var b = a;
a = 3;
// a = 3, b = 2
Call By Reference
- When you declare a
non-primitive(objects) type(array, object, function, date, regx) variable
a and b, it will has own memory location and store it's own value in it, then assign b equal to a, bdoesn't have own memory
location, a and b will has same memory location, b's valuewill change
when a's value changes.
var a = {greeting:'Hello'};
var b = a;
a.greeting = 'Hola';
console.log(a.greeting) // Hola
console.log(b.greeting) // Hola
var c = [1, 2, 3];
var d = c;
c[0] = 5;
console.log(c) // [5, 2, 3]
console.log(d) // [5, 2, 3]
Call By Sharing
- When you declare non-primitive(objects) type(array, object, function, date, regx) variable a and b, assign b equal to a, but use
Array Literals or Object Literals
to reassign a's value, b's valuewill not change
when a's value changes.- Related Reference: 談談 JavaScript 中 by reference 和 by value 的重要觀念, 你不可不知的 JavaScript 二三事
Shallow Copy
Duplicates as little as possible
. If b is a shallow copy of a, b points to a's location in memory, bwill change
it's value when changes a.- Method => spread operator (The spread operator makes deep copies of data if the data is not nested.), object.assign
Deep Copy
Duplicates everything
. If b is a deep copy of a, a and b has it's own memory location, bwill not change
it's value when changes a.- Method => javaScript : JSON.parse(JSON.stringify(object)) (not for function), jQuery : $.extend, lodash : _.cloneDeep
- Related Reference: 關於 JS 中的淺拷貝和深拷貝, JS-淺拷貝(Shallow Copy) VS 深拷貝(Deep Copy), The Spread Operator: Deep and Shallow Copies, How to Deep Clone an Array in JavaScript
- It consists of three dots (...). The spread operator allows you to spread out elements of an iterable object such as an array, map, or set.
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arrCombined = [...arr1, ...arr2];
console.log(arrCombined); // [1, 2, 3, 4, 5, 6]
- It consists of three dots (...) which collect all remaining elements into an array.
Example_1:
const getLength = (...num) => {
console.log(num.length) // 5
}
getLength(1, 2, 3, 4, 5);
Example_2:
let avg = function(...arr) {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum / arr.length;
}
console.log(avg(1, 3, 5, 7, 9)); // 5
- Rest opeator is often used in combination with destructuring.
const numbers = [1, 2, 3, 4, 5, 6];
const [a, b, ...rest] = numbers; // a = 1, b = 2, c = [3, 4, 5, 6]
- The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
- Destructuring array or object preventing from changing original values.
const [a, b] = [1, 2]; // a = 1, b = 2
const [a, , b] = [1, 2, 3]; // a = 1, b = 3
const [a, ...b] = [1, 2, 3]; // a = 1, b = [2, 3]
const [a, b, ...c] = [1, 2, 3, 4, 5]; // a = 1, b = 2, c = [3, 4, 5]
- Related Reference: 解構賦值
Methods | push() | pop() | unshift() | shift() |
---|---|---|---|---|
ADD the element in the END of array | DELETE the element in the END of array | ADD the element in the BEGINNING of array | DELETE the element in the BEGINNING of array | |
Return | New length | The removed item | New length | The removed item |
let arr = [1, 2, 3, 4, 5];
// Push
console.log(arr.push(6)); // 6 (length)
console.log(arr); // [1, 2, 3, 4, 5, 6]
// Pop
console.log(arr.pop()); // 6
console.log(arr); // [1, 2, 3, 4, 5]
// Unshift
console.log(arr.unshift(6)); // 6 (length)
console.log(arr); // [6, 1, 2, 3, 4, 5]
// Shift
console.log(arr.shift()); // 6
console.log(arr); // [1, 2, 3, 4, 5]
Methods | slice (start index, end index) | splice (index, howmany, item1, ....., itemx) | split (separator, howmany) |
---|---|---|---|
Array, string | Array | String | |
Return a new array object | Changes the contents of an array by removing existing elements and/or adding new elements. | Splits a string object into an array | |
- Starting at the given start argument, but the end doesn't include - Negative value defines the position from the end of the array |
- Starting at the given start argument, but the end doesn't include - Negative value defines the position from the end of the array |
||
NOT changes the original array | CHANGES the original array | NOT changes the original array |
let arr1 = [1, 2, 3, 4, 5];
// Slice
Example_1:
console.log(arr1.slice(0)) // [1, 2, 3, 4, 5]
Example_2:
console.log(arr1.slice(2, 4)) // [3, 4]
Example_3:
console.log(arr1.slice(-2)) // [4, 5]
// Splice
Example_1:
// At position 1, remove 3 items:
let arr2 = [1, 2, 3, 4, 5];
arr2.splice(1, 3);
console.log(arr2); // [1, 5]
Example_2:
// At position 1, add 2 elements
let arr3 = [1, 2, 3, 4, 5];
arr3.splice(1, 2, 55, 66);
console.log(arr3); // [1, 55, 66, 4, 5]
Example_3:
// Negative index
let arr4 = [1, 2, 3, 4, 5];
arr4.splice(-2);
console.log(arr4) // [1, 2, 3]
// Split
Example_1:
let str1 = "How are you";
console.log(str1.split(" ")); // ['How', 'are', 'you']
Example_2:
let str2 = "adfgdfhgdfh";
console.log(str2.split("")) // ['a', 'd', 'f', 'g', 'd', 'f', 'h', 'g', 'd', 'f', 'h']
- Related Reference: JavaScript slice()、splice()、split() 傻傻分不清, Slice、Splice、Split 的區別
- Hoisting is JavaScript's default behavior of
moving declarations to the top
.
console.log(a); // Uncaught ReferenceError: a is not defined
console.log(a); // undefined
var a;
var v = 5;
var v;
console.log(v); // 5
function test(v) {
console.log(v) // 10
var v = 3
}
test(10)
- Only hoists declarations, not initializations.
console.log(a); // undefined
var a = 5;
- Not only
hoists variable, also hoists function
, and the function's priority is higher than variable.
console.log(a) // function a(){}
var a;
function a(){};
- JavaScript in
strict mode(use strict)
doesnot allow variables to be used if they are not declared
.- You can use
let/const instead of var to avoid hoisting
, actually let/const has hoisting, but they haveTDZ(Temporal Dead Zone)
.
- This strict context
prevents certain actions from being taken and throws more exceptions
.- Using strict mode, don’t allow to use a variable without declaring it, duplicating a parameter name is not allowed, etc.
- Related Reference: 我知道你懂 hoisting,可是你了解到多深?
Let and Const is block scope, Var is function scope
.
function varFunction () {
var ming = 'May';
if (true) {
var ming = 'Joe';
}
console.log(ming); // Joe
}
function letFunction () {
let ming = 'May';
if (true) {
let ming = 'Joe';
}
console.log(ming); // May
}
varFunction();
letFunction();
- Compare var and let in loop
// With var we have a function scope, and only one shared binding for all of we loop iteration
for (var i = 0; i < 10; i++) {
setTimeout(function () {
console.log('execute ' + i + ' times; ');
}, 10);
}
// execute 10 times; execute 10 times; execute 10 times; execute 10 times; execute 10 times; execute 10 times; execute 10 times; execute 10 times; execute 10 times; execute 10 times;
// With let we have a block scope and when used in the for loop we get a new binding for each iteration
for (let i = 0; i < 10; i++) {
setTimeout(function () {
console.log('execute ' + i + ' times;');
}, 10);
}
// execute 0 times; execute 1 times; execute 2 times; execute 3 times; execute 4 times; execute 5 times; execute 6 times; execute 7 times; execute 8 times; execute 9 times;
Let is for declare variables
.Const is for declare const variables
, need initialize in declaration,can't reassignment
.
const a = 10;
a = 20; // TypeError: Assignment to constant variable.
- Related Reference: ES6 開始的新生活 let, const
- Block scope is everything inside a set of braces
{block scope here}
- A block scope is sometimes the same as a function scope.
function test(x) {
// this is both a block scope and a function scope
let y = 5;
if (x) {
// this is a smaller block scope that is not the same as the function scope
let z = 1;
}
}
function foo() {
if (true) {
var a = 1;
let b = 2;
const c = 3;
}
console.log(a); // 1
console.log(b); // b is not defined
console.log(c); // c is not defined
}
- Related Reference: let 與 const, ES6 開始的新生活 let, const
Local Scope
- Variables
declared within a JavaScript function
, becomelocal
to the function.- Local variables have Function scope: They can only be accessed within the function.
// code here CAN NOT use carName
function myFunction() {
var carName = "Volvo";
// code here CAN use carName
}
Global Scope
- A variable
declared outside a function
, becomesglobal
.- A global variable has global scope: All scripts and functions on a web page can access it.
var carName = "Volvo";
// code here can use carName
function myFunction() {
// code here can also use carName
}
- If you
assign a value to a variable that has not been declared
, it will automatically become aglobal
variable.- This code example will declare a global variable carName, even if the value is assigned inside a function.
myFunction();
// code here also can use carName
function myFunction() {
carName = "Volvo";
// code here can use carName
}
- TDZ is short of
Temporal Dead Zone
. You will get error notification if you try to access a variableafter hoisting and before initialization which declared with let or const
.
function test() {
var a = 1; // Start varable c's TDZ
var b = 2;
console.log(c); // Uncaught ReferenceError: Cannot access 'c' before initialization
if (a > 1) {
console.log(a);
}
let c = 10 // End varable c's TDZ
}
test();
- Related Reference: 我知道你懂 hoisting,可是你了解到多深?
- The this keyword refers to an object, the
value of this is determined by how a function is called
.
Default Binding
- In a JavaScript
function(default)
, the owner of the function is theglobal object
, so this refers to theglobal object
.
var a = 123;
function foo() {
console.log(this.a);
}
foo(); // 123
- In a JavaScript
function(strict)
, strict modedoes not allow default binding
, So in strict mode is undefined.
"use strict";
var a = 123;
function foo() {
console.log(this.a);
}
foo(); // undefined
Implicit Binding
- In an
object method
, this refers to theowner
of the method.
function func() {
console.log( this.a );
}
var obj = {
a: 2,
foo: func
};
func(); // undefined
obj.foo(); // 2
- In HTML
event handlers
, this refers to the HTML element that received the event.
<button onclick="this.style.display='none'">Click to Remove Me!</button>
// The button will disappear when click the button
Explicit Binding
- Use
another variable
to temp save this.
let el = document.getElementById('app');
el.addEventListener("click", function(event) {
var that = this;
console.log(this.textContent); // show the textcontent
innerFunc();
function innerFunc() {
console.log(this.textContent); // undefined
console.log(that.textContent); // show the textcontent
};
}, false);
- Use
call(), apply()
to execute the function.
var person = {
name: "Kuro",
hello: function(thing, whom) {
console.log(this.name + " says " + thing + " to " + whom);
}
}
var person2 = {
name: "Jack"
};
person.hello("love you", "Amy"); // Kuro says love you to Amy
person.hello.call(person, 'love you', 'Amy') // Kuro says love you to Amy
person.hello.apply(person, ["love you", "Amy"]); // Kuro says love you to Amy
person.hello.call(person2, "miss you", "Amy"); // Jack says miss you to Amy
person.hello.apply(person2, ["miss you", "Amy"]); // Jack says miss you to Amy
- Use
bind()
to creates a new function that will force the this inside the function to be the parameter passed to bind().
var obj = {
x: 123
};
var func = function () {
console.log(this.x);
};
func(); // undefined
func.bind(obj)(); // 123
New Binding
function foo(a) {
this.a = a;
}
var obj = new foo(123);
console.log( obj.a ); // 123
- Bind() is when you want that function to later be called with a certain context, useful in events. Use call() or apply() when you want to invoke the function immediately, and modify the context. Fundamental difference is that call() accepts an argument list, while apply() accepts a single array of arguments. The difference is that call() takes the function arguments separately, and apply() takes the function arguments in an array.
Take a function as another function's parameter, called by another function
.- Control the sequence of function execute.
window.setTimeout(function() { ... }, 1000);
- Callback functions allow us to do something with data at a later time.
- Too much callback will cause callback hell, we can use promise to prevent it.
- Related Reference: 重新認識 JavaScript: Day 18 Callback Function 與 IIFE
Promise is guarantee to do specfic things after an asynchronous action is resolved or rejected
, one of the ways we can deal with asynchronous operations, prevent callback hell. It takes two parameters, one for success (resolve) and one for fail (reject) :
const myPromise = new Promise((resolve, reject) => {
// condition
});
- A promise starts in the
pending state which indicates that the promise hasn’t completed
, it ends with either success (resolve) or fail (reject) state, and the value won't be change when the states of promise parse to resolve or reject :
(1) Resolved: The state of a promise representing a successful operation.
(2) Rejected: The state of a promise representing a failed operation.
(3) Pending: Initial state, before the promise succeeds or fails.
const myPromise = new Promise((resolve, reject) => {
let condition;
if(condition is met) {
resolve('Promise is resolved successfully.');
} else {
reject('Promise is rejected');
}
});
- How to deal with states :
(1) then(): If the promise getsresolved
, the then() method is called, then we can decide what to do with the resolved promise. then() accepts two function arguments, the first handler supplied to it will be called if the promise is resolved, The second one will be called if the promise is rejected.
(2) catch(): If the promise getsrejected
, it will jump to the catch() method.
(3) finally(): Execute thesame piece of code whether the promise is resolved or rejected
.
(4) all(): Creates a new promise that will be resolved when all of promises are resolved. If any of the promises are rejected, the returned promise will be rejected immediately and will provide the value of the promise that was rejected.
(5) Keep waiting : During pending.
myPromise.then((message) => {
console.log(message);
}).catch((message) => {
console.log(message);
});
- You execute something synchronously, you need to wait for it to finish before moving on to another task. When you execute something asynchronously, you can move on to another task before it finishes.
- Related Reference: 簡單理解 JavaScript Async 和 Await, Async-Await, 認識同步與非同步 — Callback + Promise + Async/Await
- Async and Await is
syntax sugar for promises
in javaScript.- Await ensures executing next step
after specific operations
.- An Await operand can
only be used inside an Async function
.- The Async functions return a promise.
async function fetchData() {
await a();
...... // Execute after a
await b();
...... // Execute after b
}
fetchData();
fetchData().then(() => {
...... // Execute after fetchData
});
- Expression: Any unit of code that can be evaluated to a value is an expression.
1;
1 + 2;
"Hello";
10 > 9;
- Statements: A statement is an instruction to perform a specific action. Such actions include creating a variable or a function, looping through an array of elements, evaluating code based on a specific condition etc. JavaScript programs are actually a sequence of statements.
if (expression)
statement 1
else
statement 2
- Function Statement :
(1) A function created with a name.
function statement(item) {
console.log('Function statement example' + item);
}
(2) Function declarations are hoisted.
callTest(); // 123
function callTest() {
console.log(123);
}
callTest(); // 123
- Function Expression :
(1) The name may be omitted in function expressions, making that function anonymous.
var expression = function(item) {
console.log('Function expression example'+ item);
}
(2) Function declarations are not
hoisted.
callTest(); // callTest is not a function
var callTest = function() {
console.log(123);
}
callTest(); // 123
- Related Reference: [筆記] 進一步談 JavaScript 中函式的建立 ─function statements and function expressions
- (pronounced 'iffy') Is a function
defined as an expression and executed immediately after creation
.- By wrapping our function in parenthesis, we tell the parser to parse our JavaScript as a function expression, the enclosing parenthesis at the end of IIFE are used to invoke functions.
(function() {
//...
})();
- We can’t access the variable superSecret outside of the IIFE. All of the code within our IIFE stays within the private scope of our function. Is a good way at protecting the scope of your function and the variables within it, ensures that code inside IIFE does not interfere with other code or be interfered by another code so code is safe.
(function() {
var superSecret = 195;
})()
console.log(superSecret); // Uncaught ReferenceError: superSecret is not defined
- Yes, but with consequences: Creating a named function pollutes the global name space. It also means the named function is hanging around also readily available,
it could accidentally be invoked again
.IIFE isn’t named and therefor can’t accidentally be called later — avoiding any potential security implications
.- Related Reference: 重新認識 JavaScript: Day 18 Callback Function 與 IIFE, JavaScript: What the heck is an Immediately-Invoked Function Expression?
- First Class Function means that
you can do the things to the functions same as to other types(objects, string, boolean, numbers)
.
(1) Functions are objects.
(2) Can be passed as an argument to other functions.
(3) Can be assigned as a parameter.
(4) Can be returned by another function.
(5) Function have properties.- Related Reference: [筆記] JavaScript 中函式就是一種物件 ─ 談談 first class function(一等公民函式)
- To match one of the criteria as below
(1) Takes one or more functions as arguments.
// Higher Order Function
function higherOrderFunctio(callback) {
console.log("higherOrderFunction");
callback();
}
function callbackFunction() {
console.log("callbackFunction");
}
// Callback Function
higherOrderFunction(callbackFunction);
(2) Returns a function as its result.
// Higher Order Function
function higherOrderFunction) {
console.log("higherOrderFunction");
return function(arg1) {
console.log(arg1 + "...");
};
}
// Returned Function
var returnedFunction = higherOrderFunction();
returnedFunction("returnedFunction");
- forEach(), map(), reduce(), filter(), etc. are HOFs.
- Related Reference: JavaScript 什麼是 Higher Order Function?
- Exapmle: Event Bubbling and Capturing
(1) Capturing phase: the event goes down to the element.
(2) Target phase: the event reached the target element triggers two times, as we’ve set two listeners: capturing and bubbling).
(3) Bubbling phase: the event bubbles up from the element.- Using
stopPropagation()
when you have JavaScript running on the same event of nested elements.- Related Reference: Event Flow: capture, target, and bubbling , Event Capturing and Bubbling, 瀏覽器事件:Event Bubbling, Event Capturing 及 Event Delegation
- Using
preventDefault()
to prevent default actions that browsers make when an event is triggered.- Such as you may want to do some data validation, data checks, processing, configuring headers, and so on before sending the request to a URL.
const form = document.getElementById('form');
form.addEventListener('submit', (event) => {
event.preventDefault();
// process data and submit a request manually
})
- map(): Returns new array with transformed elements, leaving back original array unchanged.
- forEach(): Like a for loop, but is more readable and intuitive. Use it when we want to perform a specific action for each element of an array.
- filter(): Return an array which that match the criteria.
- find(): Returns the first element in an array that satisfies a provided function.
- reduce(): Return a value by running the reducer across all elements of the array, leaving back original array unchanged.
let people = [
{
name: 'Casper',
like: 'Noodles',
age: 18
},
{
name: 'Wang',
like: 'Rice',
age: 24
},
{
name: 'Bobo',
like: 'Steak',
age: 1
},
{
name: 'Andy',
like: 'Fish',
age: 3
}
];
// Map
let map = people.map((item) => item.age + 1);
console.log(map); // [19, 25, 2, 4]
// Foreach
people.forEach((item) => console.log(item.name + " likes " + item.like); )
// Casper likes Noodles
// Wang likes Rice
// Bobo likes Steak
// Andy likes Fish
// Filter
let filter = people.filter((item) => item.age <= 3)
console.log(filter); // [{name: 'Bobo', like: 'Steak', age: 1}, {name: 'Andy', like: 'Fish', age: 3}]
// Find
let find = people.find((item) => item.age <= 3)
console.log(find) // {name: 'Bobo', like: 'Steak', age: 1}
// Reduce
const agesArr = people.map((item) => item.age);
const reduce = agesArr.reduce((accumulator, current) => accumulator + current
);
console.log(reduce); // 46
Methods | map() | foEach() |
---|---|---|
Return | Returns a new array | DOES NOT return a new array, returns undefined |
DOES NOT change the original array | ||
Ability to chain other methods | Can't chain other methods |
- Related Reference: The Differences Between forEach() and map() that Every Developer Should Know
const object = {
"num": 1,
"str": "Hello World",
"obj": {
"x": 5
}
};
// Dot notation
const val = object.obj.x;
console.log(val); // 5
// Bracket notation
const val = object["obj"]["x"];
console.log(val); // 5
// Destructuring Syntax
const {num, str} = object;
console.log(num, str); // 1 "Hello World"
let obj = {name : "Erika", age : 18}
// Object.keys(), Object.value() and Object.entries returns an array
for (let key of Object.keys(obj)) {
console.log(key + ","); // name, age
}
for (let value of Object.values(obj)) {
console.log(value + ","); // Erika, 18
}
for (let [key, value] of Object.entries(obj)) {
console.log(key + " = " + value + ","); // name = Erika, age = 18
}
// Use forEach
Object.keys(obj).forEach((key) => console.log(key + ",")) // name, age
Object.values(obj).forEach((val) => console.log(val + ",")) // Erika, 18
Object.keys(obj).forEach((key) => console.log(key + " = " + obj[key] + ",")) // name = Erika, age = 18
Object.entries(obj).forEach((item) => console.log(item[0] + " = " + item[1] + ",")) // name = Erika, age = 18
Object.entries(obj).forEach(([key, value]) => console.log(key + " = " + value + ",")) // name = Erika, age = 18
let map = new Map();
let arr = ["Erika", "Joe", "Ray"];
for (let i = 0; i < arr.length; i++) {
map.set(i, arr[i]);
}
for (let [key] of map) {
console.log(key + ","); // 0, 1, 2
}
for (let [, val] of map) {
console.log(val + ","); // Erika, Joe, Ray
}
for (let key of map.keys()) {
console.log(key + ","); // 0, 1, 2
}
for (let val of map.values()) {
console.log(val + ","); // Erika, Joe, Ray
}
for (let [key, value] of map) {
console.log(key + " = " + value + ","); // 0 = Erika, 1 = Joe, 2 = Ray
}
map.forEach((val, key) => console.log(key + " = " + val + ",")) // 0 = Erika, 1 = Joe, 2 = Ray
- The set object lets you store unique values of any type, whether primitive values or object references.
- Set
doesn't allow duplicate values
.
let arr = [1, 2, 2, 3];
// Check if a value is in a set object
const mySet = new Set(arr);
console.log(mySet(1)); // true
// Remove the duplicate value
let arr2 = [...new Set(arr)];
console.log(arr2); // [1, 2, 3]
let arr = [1, 2, 3, 4, 2, 3, 3];
let set = new Set(arr);
for (let val of set) console.log(val) // 1, 2, 3, 4
set.forEach(val => console.log(val)) // 1, 2, 3, 4
- Currying is transforming a function with multiple arguments into a sequence of nesting functions. It returns a new function that expects the next argument inline.
- We can use currry to reuse function instead of creating function repeatedly.
// Before currying
function minusFunc(x, y) {
return x + y;
}
console.log(1, 2); // 3
// After currying
// Syntax_1:
function minusFunc(x) {
return function(y) {
return x + y;
}
}
const returnFunc = minusFunc(1);
console.log(returnFunc); // Function
console.log(returnFunc(2)); // 3
console.log(returnFunc(5)); // 6
console.log(minusFunc(1)(2)); // 3
// Syntax_2:
const minusFunc = (x) => (y) => x - y;
const retuernFunc = minusFunc(1);
console.log(returnFunc); // Function
console.log(retuernFunc(2)); // -1
console.log(retuernFunc(5)); // -4
console.log(minusFunc(1)(5)); // -4
- If we use the global variables in the wrong way, may cause some problems like:
var count = 0;
function hamster() {
count += 1;
console.log(count + ' hamster(s)');
}
var count = 0;
function cat() {
count += 1;
console.log(count + ' cat(s)');
}
hamster(); // 1 hamster(s)
hamster(); // 2 hamster(s)
cat(); // 3 cat(s), but we expect 1 cat(s)
cat(); // 4 cat(s), but we expect 2 cat(s)
cat(); // 5 cat(s), but we expect 3 cat(s)
hamster(); // 6 hamster(s), but we expect 3 hamster(s)
Closure uses outer function returns the inner function (which we really want to execute) to let us have private variable without affected by environment
.
function hamster() {
var count = 0;
function countHamster() {
count += 1;
console.log(count + ' hamster(s)');
}
return countHamster;
}
function cat() {
var count = 0;
function countCat() {
count += 1;
console.log(count + ' cat(s)');
}
return countCat;
}
const countHamster = hamster();
const countCat = cat();
countHamster(); // 1 hamster(s)
countHamster(); // 2 hamster(s)
countCat(); // 1 cat(s)
countCat(); // 2 cat(s)
countCat(); // 3 cat(s)
countHamster(); // 3 hamster(s)
- Improve code by using anonymous and arrow function.
function hamster() {
var count = 0;
return() => {
count += 1;
console.log(count + ' hamster(s)');
}
}
function cat() {
var count = 0;
return() => {
count += 1;
console.log(count + ' cat(s)');
}
}
const countHamster = hamster();
const countCat = cat();
countHamster(); // 1 hamster(s)
countHamster(); // 2 hamster(s)
countCat(); // 1 cat(s)
countCat(); // 2 cat(s)
countCat(); // 3 cat(s)
countHamster(); // 3 hamster(s);
- Even use the same outer function, variables don't disturb each other cause the excute environment is different.
function animalCounter(name) {
var count = 0;
return() => {
count += 1;
console.log(count + ' ' + name);
}
}
const hamsterCounter = animalCounter('hamster(s)');
const catCounter = animalCounter('cat(s)');
const dogCounter = animalCounter('dog(s)');
hamsterCounter(); // 1 hamster(s)
catCounter(); // 1 cat(s)
catCounter(); // 2 cat(s)
dogCounter(); // 1 dog(s)
dogCounter(); // 2 dog(s)
dogCounter(); // 3 dog(s)
hamsterCounter(); // 2 hamster(s)
- We can also use the
let
to solve this problem.- Related Reference: 深入淺出瞭解 JavaScript 閉包(closure)
- Function composition is the process of combining two or more functions to produce a new function.
const double = (x) => x * 2;
const square = (y) => y * y;
const minus = (z) => z - 10;
// Before implementing the funcution composition
// Method_1:
let a = double(1);
let b = square(a);
console.log('Method 1', b); // 4
// Method_2:
console.log('Method 2', square(double(1))); // 4
// After implementing the funcution composition
// For only 2 functions
const composeForTwo = (fun1, fun2) => x => fun1(fun2(1));
console.log('Function composition for 2 functons', composeForTwo(square, double)(1)); // 4
// For mutiple functions
const compose = (...fcs) => x => fcs.reduceRight((val, fc) => fc(val), x);
console.log('Function composition for mutiple functions', compose(minus, square, double)(1)); // -6
- Stack is a data structure which follows a order
LIFO (Last In First Out)
in which the operations are performed.- Related Reference: 解釋 Event Loop ( 上 ) --- Call Stack
- Queue is a data structure which follows a order
FIFO (First In First Out)
in which the operations are performed.- Related Reference: 解釋 Event Loop ( 下 ) --- Task Queue ( Callback Queue )
- The call stack is what a program uses to keep track of method calls.
- The call stack is made up of stack frames.
function a() {
function b() {
function c() {
console.log('This is c()');
}
c();
console.log('This is b()');
}
b();
console.log('This is a()');
}
a();
// This is c();
// This is b();
// This is a();
- A stack overflow is a runtime error that happens
when a program runs out of memory in the call stack
.
- This is where the
asynchronous code
gets pushed to, and waits for the execution.- The tasks are broken down further into
Macrotasks and Mircotasks
, and thepriority Mircotasks is higher than Macrotasks
.
(1)Macrotasks: setTimeout, setInterval, I/O, UI Rendering
.
(2)Mircotasks: Promises, MutationObserver
.
- Apart from callback queue, reserved only for new Promise() functionality.
- Process: A process can have anywhere from just one thread to many threads.
- Threaded: A thread is the unit of execution within a process.
single thread means it can only do one thing at the same time
.- Runtime: Where your program will be executed. It determines what global objects your program can access and it can also impact how it runs. This article covers the two JavaScript runtime environments:
(1) The runtime environment of a browser (like Chrome, or Firefox).
(2) The Node runtime environment.- Web APIs: The Web APIs are provided by the web browser that gives additional functionality to the V8 engine, like the DOM, AJAX, setTimeout and much more.
- Heap: It's not a data structure here, this is where all the memory allocation happens for your variables, that you have defined in your program.
- JavaScript is a
single-threaded
programming language which can run at variousruntime
, once your browser starts processing too many tasks in the call stack, it may stop being responsive for a long time, even block the UI thread, and the user can't click around, scroll the page, and so on.- In order to run the make sure
every process isolated and avoid a web page with infinite loops or heavy processing to block your entire browser when using web APIs
, theevent loop
continuous monitoing thecall stack and the callback queue
. If the call stack is empty, it will take the first event from the queue and will push it to the call stack, which effectively runs it.
console.log('start');
setTimeout(() => {
console.log('setTimeout1');
})
Promise.resolve()
.then(() => {
console.log('Promise1');
})
.then(()=> {
console.log('Promise2');
})
setTimeout(() => {
console.log('setTimeout2');
})
console.log('end');
// Result
'start'
'end'
'Promise1'
'Promise2'
'setTimeout1'
'setTimeout2'
- Related Reference: How JavaScript works: an overview of the engine, the runtime, and the call stack, How JavaScript works: Event loop and the rise of Async programming + 5 ways to better coding with async/await,Understanding Event Loop, Call Stack, Event & Job Queue in Javascript,JS底層學習筆記 - EventLoop, JavaScript 深入淺出 Microtasks & Marcotask
- Functional programming empazies on pure, higher order functions, take function as first class, voiding mutating data and side effect.
- Related Reference: What is Functional Programming?
- Allows you to avoid confusing problems and errors in the code
- Easier to test and execute Unit testing and debug FP Code.
- Parallel processing and concurrency
- Hot code deployment and fault tolerance
- Offers better modularity with a shorter code
- Increased productivity of the developer
- Supports Nested Functions
- Functional Constructs like Lazy Map & Lists, etc.
- Allows effective use of Lambda Calculus
- Pure Functions = Consistent Results
- The first example returns a value based on the given parameters, regardless of where/when you call it.
(1) Its return value is the same for the same arguments.
(2) Its evaluation has no side effects.
// Pure Function
const add = (x, y) => x + y;
console.log(add(2, 4)); // 6
- Impure Functions = Inconsistent Results
- The second example returns nothing. It relies on shared state to do its job by incrementing a variable outside of its own scope. In the example : The first time results in 6, next time is 10 and so on.
// Impure Function
let x = 2;
const add = (y) => x += y;
console.log(add(4)); // 6
console.log(add(4)); // 10
- Related Reference: What Is a Pure Function in JavaScript?
- Recursion is a process of calling itself. A function that calls itself is called a recursive function. A recursive function must have a condition to stop calling itself. Otherwise, the function is called indefinitely.
function recu(i) {
if(i < 10) {
i++;
return recu(i);
}
return i;
}
console.log(recu(1))l // 10
- Try Catch: Can allow user to use website normarlly although the error occor. The Try statement lets you test a block of code for errors, the catch statement lets you handle the error.
- Throw: It will terminate the further execution.
- Throw new Error(): The difference between throw and throw new Error() is the format {name: 'Error', message: 'String you pass in the constructor'}, you can also customize the information you want to debug such as transaction number.
try {
throw "I'm Erika"; // I'm Erika
throw Error("I'm Joe"); // Error: I'm Joe, if the above line exists then this line won't never show
throw new Error("I'm Ray"); // Error: I'm Ray, if the above two lines exist then this line won't never show
console.log("You'll never reach me if any above code line shows")
} catch(e) {
console.log(e);
}
- All JavaScript objects inherit properties and methods from a prototype.
- Prototype property allows you to
add new properties
to object constructors.
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.nationality = "English";
- Prototype property allows you to
add new methods
to object constructors.
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.name = function() {
return this.firstName + " " + this.lastName;
};
prototype is a property of a Function object
. It is the prototype of objects constructed by that function.__ proto __ (pronounced as dunder proto or double underscore proto) is internal property of an object, pointing to its prototype
. Current standards provide an equivalent Object.getPrototypeOf(O) method.
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.log = function () {
console.log(this.name + ', age:' + this.age);
}
var nick = new Person('nick', 18);
console.log(nick.__proto__ === Person.prototype); // true
console.log(nick.prototype === undefined); // true
- Related Reference: ** proto ** VS. prototype in JavaScript , 該來理解 JavaScript 的原型鍊了
- If you try to call a property on an object, JavaScript will go to the prototype object and look for it, until it finds it. If it doesn't find the specific property that you're looking for, it'll return undefined for you.
- Related Reference : JavaScript Fundamentals: Prototype Chains
- Event delegation allows you to
avoid adding event listeners to specific nodes, instead, the event listener is added to one parent.
That event listener analyzes bubbled events to find a match on child elements.- Related Reference: [教學] 瀏覽器事件:Event Bubbling, Event Capturing 及 Event Delegation, What is DOM Event delegation?
- parseInt(): convert binary string to number
- toString(): convert number to binary string
// Convert binary string to number
let binaryStr = "1011";
let num = parseInt(binaryStr, 2);
console.log(num); // 11
// Convert number to binary string
let num = 34;
let binaryStr = num.toString(2);
console.log(binaryStr); // "100010"
Library | Framework |
---|---|
A set of assistance modules, objects, classes, functions, pre-written code, and so on. | Includes a variety of APIs, compilers, support applications, libraries, and so on. |
Can be easily substituted by another library. | Are tough to replace. |
When we call a method from a library, we are in control. | Inversion of control, i.e. the framework calls us. |
Since developing a library needs less code, performance and load time are improved. | The construction of a framework necessitates large amounts of code, which reduces performance and increases load time. |
Libraries can be simply linked into existing programs to add specific functionality. | It is tough to incorporate a framework seamlessly into an existing project. |
- Related Reference: Difference Between Framework Vs Library
- To do somthing after receive the data from API calls.
- With JavaScript we can build websites, mobile apps, web apps, and writing back-end code, It works on many platforms and environments. Many new features in ES6 and ES7 such as spread operator, promise, async, and await can greatly increase our ease of development. JavaScript is also a foundation of frameworks such as React, Vue, etc. We can use the frameworks to solve many real-world problems and extend the language.
- JavaScript is very relaxed about the difference between strings and numbers. such as using string + number will be string, and using string will be number. It might cause the error code, but we can us TypeScript to prevent this simple error occurs.
const arr = [1, 2, 3];
const myMap1 = (arr, func) => {
let newArr = [];
for(let i = 0; i < arr.length; i++) {
let result = func(arr[i])
newArr.push(result);
}
return newArr;
}
console.log(myMap1(arr, num => num + 1)); // [2, 3, 4]
// Without using for loop
const myMap2 = (oldArr, func, newArr = []) => {
if (oldArr.length === 0) {
return newArr;
} else {
let [val, ...rest] = oldArr;
let updateArr = [...newArr, func(val)];
return myMap2(rest, func, updateArr);
}
}
console.log(myMap2(arr, num => num + 1)); // [2, 3, 4]
- Related Reference: Javascript - Writing Map as a Recursive Function
type MyFnType<Type> = (arg1: Type) => Type;
const myMap1 = <Type>(arr: Type[], fn: MyFnType<Type>): Type[] => {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
newArr.push(fn(arr[i]));
}
return newArr;
};
console.log(myMap1(arr, (x: number) => x + 1));
// Without using for loop
const myMap2 = <Type>(
oldArr: Type[],
fn: MyFnType<Type>,
newArr: Type[] = []
): Type[] => {
if (oldArr.length <= 0) {
return newArr;
} else {
const [val, ...rest] = oldArr;
newArr.push(fn(val));
return myMap2(rest, fn, newArr);
}
};
console.log(myMap2(arr, (x: number) => x + 1));