Javascript Basic

AngularJS study path

Posted by Shi

Closure

https://stackoverflow.com/questions/111102/how-do-javascript-closures-work?rq=1

Sleep function in network request

function* sleep() {
  yield new Promise((resolve) => {
    setTimeout(() => {
      resolve(5);
    }, 1000);
  });
}
 
yield sleep().next().value.then((n) => console.log(n));

Assign

const authTemp = Object.assign({}, result, {
  auth: {
    ...result.auth,
    token: password,
  },
});
const auth = { ...authTemp.auth };

Array

var things = [
    1,
    '2',
    function(){
        alert('Hello');
    }
]
//Call function in array
things[2]();

Size

arr.length

1. Copy

arr.slice() //is used to return a new array that is same as the original one

2. Delete elements

  1. Remove the first item of an array

    arr.shift()
    
  2. To delete elements in an array, you pass two arguments to the splice() method as follows:

Array.splice(position,num);

position argument specifies the position of the first item to delete

num argument determines the number of element to delete.

Returns deleted elements.

let scores = [1, 2, 3, 4, 5];
let deletedScores = scores.splice(1, 2);
console.log(deletedScores); // [2, 3]
console.log(scores); //  [1, 4, 5]

3. Insert elements in certain position

Array.splice(position,0,new_element_1,new_element_2,...);
  • The position argument specifies the starting position in the array that the new elements will be inserted.
  • The second argument is zero (0) that instructs the splice() method to not delete any elements.
  • The third argument, fourth argument, and so on are the new elements that are inserted into the array.
var colors = ['red', 'green', 'blue'];
colors.splice(2, 0, 'purple');
console.log(colors); // ["red", "green", "purple", "blue"]

4. Replace element

var languages = ['C', 'C++', 'Java', 'JavaScript'];

// Replace one element
languages.splice(1, 1, 'Python');
console.log(languages); // ["C", "Python", "Java", "JavaScript"]

// Replace one element by multiple elements
languages.splice(2,1,'C#','Swift','Go');
console.log(languages); // ["C", "Python", "C#", "Swift", "Go", "JavaScript"]

5. Find

const ticket = ticketList.find((ticketTemp) => ticketTemp.id.id === ticketId);

6. Sub array

The slice() method returns a shallow copy of a portion of an array into a new array

arr.slice(begin, end)

If begin is undefined, slice begins from index 0.

If end is undefined, slice extracts through the end of the sequence (arr.length).

7. Loop

let productId = 42;
for (let productId = 0; productId < 10; productId++)
{

}
    const slotConfigIdsTemp = [];
    if (slotConfigIds.length > 0) {
      slotConfigIds.forEach((value) => {
        slotConfigIdsTemp.push(value.id);
      });
    }

Bracket notation

var cat = {
    name: 'Fluffy', 
    color: 'White'
}

display(cat['color']) //Produce same result like: display(cat.color)

//You can also add a property using bracket notation
cat['eye'] = 'Green'
display(cat['eye']) //Print: Green

Property description

var cat = {
    name: 'Fluffy', 
    color: 'White'
}

//Display property description
display(Object.getOwnPropertyDescriptor(cat, 'name'))

//Make a property immutable
Object.defineProperty(cat, 'name', 
  {
  	writable: false
  })
Object.freeze(cat.name)

//Loop every properties in object
for(var propertyName in cat){
	display(propertyName) // Print: name color
	display(cat[propertyName]) // Print: Fluffy White
}

//Set property enumerable
Object.defineProperty(cat, 'name', 
  {
  	enumerable: false // not enumerable: not to be print in iteration
  })
  

//Set property configuarable
Object.defineProperty(cat, 'name', 
  {
  	configuarable: false // not configuarable: can not redefine property
  })

//getter and setter
Object.defineProperty(cat, 'fullName', 
  {
    get: function() {
      return this.name.first + ' ' + this.name.last
    },
    set: function(value) {
      var nameParts = value.split(' ')
      this.name.first = nameParts[0]
      this.name.last = nameParts[1]
    }
  })
  
//Set name
cat.fullName = 'Muffin Top'
//Get name
display(cat.fullName)

//delete property
delete cat.name

//JSONrization
JSON.stringify(cat)

Prototype

Use to inherit from or extend functionality in other objects.

Every function has a prototype

var myFunc = function(){}
display(myFunc.prototype) // Output: {}

Object does not hava a prototype but has proto

var cat = {name: 'Carlo'}
display(cat.__proto__) // Output: Object {}
	
Object.defineProperty(Array.prototype, 'lastElement', 
  {
    get: function() {
      return this[this.length - 1]
    }
  })

//Call lastElement method 
var arr = ['red','blue','green'] // Same as: var arr = new Array('red','blue','green')
var last = arr.lastElement

Usage

function Cat(name, color) {
    this.name = name
    this.color = color
}
var carlo = new Cat('Carlo','white')

Cat.prototype === carlo.__proto___//Return true. They are pointing to the exact same instance of an object

Cat.prototype.age = 3

display(Cat.prototype) //Output: Cat{ age:3 }
display(carlo.__proto___) //Output: Cat{ age:3 }

display(carlo.hasOwnProperty('age')) // Output: false

carlo.age = 5 
display(carlo.hasOwnProperty('age')) // Output: true. carlo now has his own property

Prototype chains

Create prototype chains without using class syntex

function Animal(voice){
    this.voice = voice || 'grunt'
}
Animal.prototype.speak = funciton(){
    display(this.voice)
}

function Cat(name){
    Animal.call(this, 'Meow') // Step 1 (to create a prototype chain)
    this.name = name
}

Cat.prototype = Object.create(Animal.prototype) //Step 2
Cat.prototype.constructor = Cat //Step 3

var carlo = new Cat('Carlo')
carlo.speak()

Create prototype chains using class syntex

class Animal {
  constructor(voice) {
    this.voice = voice || 'grunt'
  }
  
  speak() {
    display(this.voice)
  }
}

class Cat extends Animal {
  constructor(name, color) {
    super('Meow')
    this.name = name
    this.color = color
  }
}

var fluffy = new Cat('Fluffy', 'White')
fluffy.speak()

display(fluffy) //Output: {voice:Meow name:Fluffy color:White}

display(Object.keys(fluffy.__proto__.__proto__)) //Using class syntex, Members of classed are not enumerable. So this speak function is not an enumrable property of the animal class
display(fluffy.__proto__.__proto__.hasOwnProperty('speak')) // Output: true

Defining getters and setters

var o = {
  a: 7,
  get b() { 
    return this.a + 1;
  },
  set c(x) {
    this.a = x / 2
  }
};

console.log(o.a); // 7
console.log(o.b); // 8
o.c = 50;
console.log(o.a); // 25

let, var, const

Always use let instead of var.

const PI = 3.1415;
PI = 3; // TypeError: Assignment to constant variable.

const foo = Object.freeze({}); //Const for an object

Iteration


var categories = ['hardware', 'software', 'vaporware'];

for (var item of categories) {

}

Template Literals

let invoiceNum = '1350';
console.log(`Invoice Number: ${invoiceNum}`);

Destructuring

let salary = ['32000', '50000'];
let low, average, high;
[ low, average, high = '88000' ] = salary;
console.log(average); //Output: 50000

let salary = ['32000', '50000', '75000'];
let [ low, ...remaining ] = salary;
console.log(remaining); //Output: ["50000", "75000"]

let salary = {
	low: '32000'
	average: '50000'
	high: '75000'
};
let { low, average, high} = salary;
console.log(high); //Output: 75000

Key interpelation

[payload.prop]:payload.value
//key will be determained at runtime 

Arrow functions (Lambda Functions)

(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression // equivalent to:  => { return expression; }

// Parentheses are optional when there's only one parameter:
(singleParam) => { statements }
singleParam => { statements }

// A function with no parameters requires parentheses:
() => { statements }

function(s){ 
  return s.length 
} 
EQUALS
s => s.length

i.e.
var foo = (x)=>10+x 
console.log(foo(10)) 

Rest and Spread Operators

The values passed must all be of the same type. In other words, rest parameters act as placeholders for multiple arguments of the same type.

i.e.
var showCategories = function (productId, ...categories) {
	console.log(categories); 
};
showCategories(123, 'search', 'advertising'); //Output: ['search', 'advertising']

i.e.
function fun1(...params) { 
   console.log(params.length); 
}  
fun1();  //Output: 0
fun1(5); //Output: 1
fun1(5, 6, 7); //Output: 3

The Function Constructor

var variablename = new Function(Arg1, Arg2..., "Function Body"); 

The Function() constructor expects any number of string arguments. The last argument is the body of the function – it can contain arbitrary JavaScript statements, separated from each other by semicolons.

Example βˆ’ Function Constructor

var func = new Function("x", "y", "return x*y;"); 
function product() { 
   var result; 
   result = func(10,20); 
   console.log("The product : "+result)
} 
product() //Output: 200

Module

Import and export functions, names etc

Traceur is a JavaScript.next-to-JavaScript-of-today compiler. traceur-compiler also babel works

Imported variable is read-only

When I import another module, the module will be executed first.

File module1.js:
export let projectId = 99;
export let projectName ='BuildIt';

File base.js:
import { projectId as id, projectName } from 'module1.js';
console.log(`${projectName} has id: ${id}`);

//Output: BuildIt has id: 99

File module1.js:
let projectName ='BuildIt';
export let projectId = 99;
export default projectName;
//Equals=== export {projectName as default, projectId}

File base.js:
import someValue from 'module1.js';
console.log(someValue);

//Output: BuildIt

Class

class Cat {
  constructor(name, color) {
    this.name = name
    this.color = color
  }
  
  speak() {
    display('Meeooow')
  }
}

var cat = new Cat('Fluffy', 'White')

display(cat)
cat.speak()

Constructor

class Project {
    constructor() {
		console.log('constructing Project');
	}
}

class SoftwareProject extends Project {
	constructor() {
		super();
		console.log('constructing SoftwareProject');
	}
}

let p = new SoftwareProject(); //Output: constructing Project /  constructing SoftwareProject

Static members

class Project {
	static getDefaultId() {
		return 99;
	}
}
console.log(Project.getDefaultId());//Output: 99

New.target

Point to the original function that called

class Project {
	constructor() {
		console.log(new.target.getDefaultId());
	}
}
class SoftwareProject extends Project {
	static getDefaultId() { return 99; }
}
var p = new SoftwareProject();//Output: 99

Symbol

const CALCULATE_EVENT_SYMBOL = Symbol('calculate event');
console.log(CALCULATE_EVENT_SYMBOL.toString()); // Output: Symbol(calculate event)
let s = Symbol('event');
let s2 = Symbol('event');
console.log(s === s2);// Output: false
let s = Symbol.for('event');
let s2 = Symbol.for('event');
console.log(s === s2);// Output: true
let article = {
	title: 'Whiteface Mountain',
	[Symbol.for('article')]: 'My Article'
};
let value = article[Symbol.for('article')];
console.log(value);// Output: My Article

Object Extensions

let a = { a: 1 }, b = { a: 5, b: 2 };
let target = {};
Object.assign(target, a, b);
console.log(target);// Output: {a: 5, b: 2}
// Object.is() replace ===
let amount = NaN;
console.log(Object.is(amount, amount));// Output: true
console.log(amount === amount);// Output: false

String

let title = 'Santa Barbara Surf Riders';
console.log(title.startsWith('Santa'));// Output: true
console.log(title.endsWith('Rider'));// Output: false
console.log(title.includes('ba'));// Output: true

var s = 'Hello world!';
//second param is the init point
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false

let wave = '\u{1f30a}'; //Unicode Character suppported
console.log(wave.repeat(10)); //Output: 🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊

Number

let sum = 408.2;
console.log(Number.isInteger(sum));// Output: false

let a = Math.pow(2, 53) - 1;
console.log(Number.isSafeInteger(a));//true
a = Math.pow(2, 53);
console.log(Number.isSafeInteger(a));//false

console.log(Math.sign(-20));// -1
console.log(Math.sign(20));// 1

//trunc() the integer part of a number
console.log(Math.trunc(27.1)); //27

Iterator

let ids = [9000, 9001, 9002];
let iter = ids[Symbol.iterator]();
iter.next();
iter.next();
console.log(iter.next());// Output: {done: false, value: 9002}

//Example 2
let idMaker = {
	[Symbol.iterator]() {
		let nextId = 8000;
		return {
			next() {
				let value = nextId>8002?undefined:nextId++;
				let done = !value;
				return { value, done };
}};}};
for (let v of idMaker)
console.log(v);// 8000 8001 8002

Generators

Similar to iterator

* indicate that the function is a generator function

function *process() {
	yield 8000;
	yield 8001;
}
let it = process();
console.log(it.next());// Output: {done: false, value: 8000}

//Example 2
function *process() {
	let nextId = 7000;
		while(true)
			yield(nextId++);
}

//This is a generator
for (let id of process()) {
if (id > 7002) break;
console.log(id);
}

Yielding in Generators

yield is a keyword in generator functions.

Yield is often proceeded by a function call that returns a promise

Redux-Saga forms a wrapper around generators that simplify manageing promises

function *process() {
	yield 42;
	yield* [1,2,3];
}

let it = process();
console.log(it.next().value);//42
console.log(it.next().value);//1
console.log(it.next().value);//2
console.log(it.next().value);//3
console.log(it.next().value);//undefined 

throw and return

function *process() {
	try {
		yield 9000;
		yield 9001;
		yield 9002;
	}
	catch(e) {
	}
}
let it = process();
console.log(it.next().value);//9000
console.log(it.throw('foo'));//{done:true, value:undefined}
console.log(it.next());//{done:true, value:undefined}

Promise

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.

new Promise( /* executor */ function(resolve, reject) { ... } );

How do I access the data in a promise? I use .then(function)

How do I catch the errors from a promise chain? I use .catch(function)

async functions don’t magically wait for themselves. You must await, or you’ll get a promise instead of the value you expect.

Basic usage

i.e.

let myFirstPromise = new Promise((resolve, reject) => {
  // We call resolve(...) when what we were doing asynchronously was successful, and reject(...) when it failed.
  // In this example, we use setTimeout(...) to simulate async code. 
  // In reality, you will probably be using something like XHR or an HTML5 API.
  setTimeout(function(){
    resolve("Success!"); // Yay! Everything went well!
  }, 250);
});

myFirstPromise.then((successMessage) => {
  // successMessage is whatever we passed in the resolve(...) function above.
  // It doesn't have to be a string, but if it is only a succeed message, it probably will be.
  console.log("Yay! " + successMessage);
}).catch((err) =>{
  console.log("Err! " + err);
});

Call order

getProcessedData(50);

//Output: 
1start async  50
2finish async  50
3finish async in func 
4process data  90

For async request

function doAsync() {
	let p = new Promise(function (resolve, reject) {
		console.log('in promise code');
		setTimeout(function () {
			console.log('resolving...');
			resolve('someData');
			// or reject('database error!');
		}, 2000);
	});
	return p;
}
let promise = doAsync();// Output: in promise code (2 second delay) resolving...

//function then take two params: success function and reject function
doAsync().then(function (value) {
	console.log('Fulfilled!'+ value);
},
function () {
	console.log('Rejected!');
})
//you can chain another function by
.then(function(value) {
	console.log('Really! ' + value);
});
//when the error occurs, you can call catch
.catch(function (reason) {
	console.log('Error: ' + reason);
});

Multiple promises

Promise.all will take an array of promises, and compose them all into a single promise, which resolves only when every child promise in the array has resolved itself.

let foo = await getFoo();
let bar = await getBar();
//Equals to 
let [foo, bar] = await Promise.all([getFoo(), getBar()]);



let p1 = new Promise(...);
let p2 = new Promise(...);
Promise.all([p1, p2]).then(
	function (value) { console.log('Ok') },
	function (reason) { console.log('Nope') }
);
// assume p1 resolves after 1 second,
// assume p2 is rejected after 2 seconds

// Output: (2 second delay) Nope
//Race returns when one task finishes
Promise.race([p1, p2]).then(
	function (value) { console.log('Ok') },
	function (reason) { console.log('Nope') }
);

// assume p1 is rejected after 3 second,

// assume p2 resolves after 5 seconds
// Output: (3 second delay) Nope

Async/Await

every async function you write will return a promise, and every single thing you await will ordinarily be a promise.

https://davidwalsh.name/async-await

Array

Array Extension

let salaries = Array.of(90000);

let amounts = [800, 810, 820];
let salaries = Array.from(amounts, v => v+100 );
console.log(salaries); //[900,910,920]

//Third param is an object which is visiable in 'this'
let amounts = [800, 810, 820];
let salaries = Array.from(amounts, function (v) {
	return v + this.adjustment;
}, { adjustment: 50 });

console.log(salaries);//[850,860,870]

// -> function do not let you change 'this', this will be always the context you setted when it appares, so you can not change it.
let amounts = [800, 810, 820];
let salaries = Array.from(amounts, v => v + this.adjustment,{ adjustment: 50 });
console.log(salaries);//[NaN, NaN, NaN]

let salaries = [600, 700, 800];
salaries.fill(900);
console.log(salaries);//[900, 900, 900]

let salaries = [600, 700, 800];
salaries.fill(900, 1);//Start to fill arrary from index 1
console.log(salaries); //[600, 900, 900]

let salaries = [600, 700, 800];
salaries.fill(900, 1, 2); //Start to fill arrary from index 1, stop at index 2 (not inclusive)
console.log(salaries);//[600, 900, 800]

let salaries = [600, 700, 800];
salaries.fill(900, -1);//Start counting from the end of array
console.log(salaries);//[600, 700, 900]

let salaries = [600, 700, 800];
let result = salaries.find(value => value >= 750);//Scan array, and for each element will call the function
console.log(result);//800

let salaries = [600, 700, 800];
let result = salaries.find(value => value >= 650); //As soon as find the element, it will stop the scan and return it
console.log(result);//700

let salaries = [600, 700, 800];
salaries.copyWithin(2, 0);// 2 refer to the destination index, 0 is the source index (start reading from)
console.log(salaries);//[600, 700, 600]

let ids = [1, 2, 3, 4, 5];
ids.copyWithin(0, 1);//Start reading from position 1, so read  2, 3, 4, 5, then place it from position 0, got [2, 3, 4, 5, 5] which the last position is not touched
console.log(ids);//[2, 3, 4, 5, 5]

let ids = [1, 2, 3, 4, 5];
ids.copyWithin(3, 0, 2);//only want to copy two values
console.log(ids//[1, 2, 3, 1, 2]

let ids = ['A', 'B', 'C'];
console.log(...ids.entries());//[0,"A"], [1,"B"], [2,"C"]  entries create an array for each element [index, value]

let ids = ['A', 'B', 'C'];
console.log(...ids.keys());//0 1 2

let ids = ['A', 'B', 'C'];
console.log(...ids.values());//A B C

ArrayBuffer and Typed Arrays

ArrayBuffer is array of 8 bytes , is useful to hold binaray data like image and video

Typed Arrays, access data in the array buffer

let buffer = new ArrayBuffer(1024); //1024 is the length of new byte array
console.log(buffer.byteLength); //1024

Map

let employee1={ name: 'Jake' };
let employee2 ={ name: 'Janet' };

let employees= new Map();
employees.set(employee1, 'ABC');
employees.set(employee2, '123');

console.log(employees.get(employee1)); //ABC

employees.delete(employee2);
console.log(employees.size);//1

employees.clear();
console.log(employees.size);//0

let arr = [
	[employee1, 'ABC'],
	[employee2, '123']

];
let employees = new Map(arr);
console.log(employees.size);//2
console.log(employees.has(employee2));//true

let list = [...employees.values()];
console.log(list);//['ABC', '123']

let list= [...employees.entries()];
console.log(list[0][1]); //ABC

//iterate map
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

Set

let perks = new Set();
perks.add('Car');
perks.add('Super Long Vacation');
perks.add('Car');

console.log(perks.size);//2

let perks= new Set([
	'Car',
	'Jet'
]);
console.log(perks.size);//2

let newPerks= new Set(perks); //newPerks is a copy of perks
console.log(newPerks.size);//2
console.log(perks.has('Jet'));//true
console.log(...perks.keys());//Car Jet
console.log(...perks.values());//Car Jet
console.log(...perks.entries());//Car,Car Jet,Jet

//Do not put object in set, they are considered as two different obj
let perks = new Set([
	{ id: 800 },
	{ id: 800 }
]);

console.log(perks.size);//2

Subclassing

class Perks extends Array{
	sum(){
		let total =0;
		this.map(v => total += v);
		return total;
	}
let a = Perks.from([5, 10, 15]);

console.log(a.sum());//30

The Reflect API

Reflect.construct(target, argumentsList[, newTarget])

class Restaurant {
	constructor(name, city) {
		console.log(`${name} in ${city}`);
	}
}

let r = Reflect.construct(Restaurant, ["Zoey's", "Goleta"]);//similar to let r= new Restaurant("Zoey's", "Goleta");
console.log(r instanceof Restaurant);//true


Note

JavaScript Style

Airbnb JavaScript Style Guide: http://airbnb.io/javascript/

Books

ECMAScript 6 ε…₯ι—¨: http://es6.ruanyifeng.com/#docs/intro