# Javascript ES6 特性逐步解析

ES6的正式版出現，簡化了以往javascript比較繁瑣的處理，也新增了一些新的feature，可以視為是語法糖，雖然底層實作還是一樣。但對開發者可以省去更多的時間，也簡潔了語法。

### Functional Programming

function fib(n) {
if (n <= 0 ) return 0;
else if (n === 1) return 1;
else return fib(n - 1) + fib(n - 2);
}
console.log(fib(10));
// 55

functional fib(n) {
var a = 0, b = 1;
for (var i = 0; i < n; i++) {
var tmp = a + b;
b = tmp;
}
}
console.log(a);

var fib = (n) = > n <= 0 ? 0 : n === 1 ? 1 : fib(n -1) + fib(n - 2);

#### Array Iteration Method: map

var square = ary => ary.map(i => i * i);
console.log(square([1, 2, 3]));
// [ 1, 4, 9 ]

#### Array Iteration Method: filter

var odd = ary => ary.filter(i => i % 2 === 1);
console.log(odd([1, 2, 3]));
// [ 1, 3 ]

#### Array Iteration Method: chaining

var squareOdd = ary => ary.filter(i => i % 2 === 1).map(i => i * i);
console.log(squareOdd([1, 2, 3]));
// [ 1, 9 ]

#### Array Iteration Method: reduce

var sum = ary => ary.reduce((prev, next) => prev + next, 0);
console.log(sum1([1, 2, 3]));
// 6

### Object-oriented Programming

• Classes/Object
• Methods/Properties
• Encapsulation
• Composition
• Inheritance
• Polymorphism

var Shape = function(x, y){
this.x = x;
this.y = y;
};
var Circle = function(x, y, radius){
Shape.call(this, x, y);
}
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
var shape = new Shape(1, 2);
var circle = new Circle(1, 2, 3);
console.log(shape instanceof Shape);
// true
console.log(circle instanceof Shape);
// true
console.log(Object.getPrototypeOf(shape) == Shape.prototype);
// true
var circle1 = Circle(2, 3, 5);
console.log(circle1 instanceof Shape);
// false

class Shape {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class Circle extends Shape {
super(x, y);
}
}
var shape = new Shape(1, 2);
var circle = new Circle(1, 2, 3);
console.log(shape);
console.log(circle);

var user = {};
user.name = 'Anderson';
user.getName = function (){ console.log('name:' + this.name);}
user.getName();
// name: Anderson
var child = Object.create(user);
child.getName();
// name: Anderson
child.name = 'Baby';
child.getName();
// name: Baby
console.log(child.__proto__ === user);
// true
var descendant = Object.create(child);
descendant.getName();
// name: Baby
console.log(descendant.__proto__);
// { name: 'Baby' }
console.log(Object.getPrototypeOf(descendant));
// { name: 'Baby' }
console.log(descendant.__proto__ === Object.getPrototypeOf(descendant));
// true
console.log(descendant.__proto__.__proto__);
// { name: 'Anderson', getName: [Function] }

#### Static Property

static的宣告主要有兩種方式，前者指向一個new出來的物件來將static的參數綁定，優點是所有呼叫該static屬性都會指到同一個記憶體位置。而後者則是使用static保留字，但每次都會new一個instance。

class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
Point.ZERO = new Point(0, 0);
console.log(Point.ZERO);
// Point { x: 0, y: 0 }
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static get ZERO() {
return new Point(0, 0);
}
}
console.log(Point.ZERO);
// Point { x: 0, y: 0 }

#### Extends Property

class Animal{
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noice.');
}
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks');
}
}
var dog = new Dog("Anderson");
dog.speak();
// Anderson barks

class Cat{
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noice.');
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(this.name + ' roars.');
}
}
var lion = new Lion("Simba");
lion.speak();
// Simba makes a noice.
// Simba roars.

### let and const

var x = 'global';
function f() {
console.log(x);
if (true) {
var x = 'local';
}
console.log(x);
}
f();
// undefined
// local

hoisting完實際執行變成如下，

var x = 'global';
function f() {
var x;
console.log(x);
if (true) {
x = 'local';
}
console.log(x);
}
f();
// undefined
// local

let x = 'global';
function f() {
console.log(x);
if (true) {
let x = 'local';
}
console.log(x);
}
f();
// global
// global

const x = 'global';
function f() {
console.log(x);
if (true) {
const x = 'local';
}
console.log(x);
}
f();
// global
// global

const x = 'global';
function f() {
if (true) {
const x = 'local';
}
x = "must error";
}
f();
// TypeError: Assignment to constant variable.

function count1to5(){
for(var i = 1; i <= 5; i++){
setTimeout(function(){
console.log(i);
}, i * 1000);
}
}
count1to5();
// 6 6 6 6 6

function count1to5(){
for(let i = 1; i <= 5; i++){
setTimeout(function(){
console.log(i);
}, i * 1000);
}
}
count1to5();
// 1 2 3 4 5

const obj = {name: 'Anderson'};
// obj = {name: 'James'}; // TypeError: Assignment to constant variable
obj.name = 'AndersonJJ';
console.log(obj);

1. 不會改變得物件使用const，會改變的就用let，不確定的話也用let，等到確定為唯讀時再改為const
2. 不要再用var，太容易產生非預期的bug了。

### String Interpolation

let customer = { name:"Anderson" };
let info = { type: "VIP", discount: 0.9 };
let message = `歡迎光臨 \${customer.name}，

console.log(message);
\\ 歡迎光臨 Anderson，
\\ 你是我們的VIP客戶，
\\ 您享有全館9折的優惠喔。

### Module

• CommonJS: NodeJS就是就是採用該方案，將需要用到的模組透過 require('xxx') 的方式使用模組，載入為同步。而模組則透過 modules.exports 的方式釋出給其他呼叫者使用。
• AMD(Asynchronous Module Definition)，使用到模組時才非同步的載入，不像CommonJS需要一開始就得載入。可以避免效能上的浪費，或是最佳化可用性。

// lib/math.js
export function suqare(x) { return x * x; }
export const pi = 3.14159;
// app1.js
import * as math from 'lib/math';
console.log(math.suqare(math.pi));
// app2.js
import { square, pi } from 'lib/math';
console.log(suqare(pi));

// lib/math2.js
export * from 'lib/math';
export const e = 2.71828;
export default (x) => Math.exp(x);
// app.js
import exp, { pi } from 'lib/math2';
console.log(exp(pi));

### Iterate Over Arrays

for 迴圈可以分別用in和of來取得陣列的索引和值，特別的是，ary.x既是陣列的宣告也同時是物件屬性的宣告方式，所以使用of 則物件不會顯示。

let ary = ['a', 'b', 'c'];
ary["4"] = "d";
ary.x = "e";
for(let v in ary){ console.log(v); } // 0 1 2 4 x
for(let v of ary){ console.log(v); } // a b c undefined d

### Array Matching

function* fib() {
let [prev, curr] = [0, 1];
while(true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
for(let n of fib()){
if(n > 5) break;
console.log(n);
}

### Object Matching

function getAccount() {
return {
name: 'Anderson',
sex: 'male',
age: '18'
}
}
const { name, age } = getAccount();
console.log(`Hi, \${name}`);
let account = { name, age };
console.log(account);
// Hi, Anderson
// { name: 'Anderson', age: '18' }

var obj1 = { a: 1 };
var obj2 = { a: 2 };
var obj3 = { a: 3 };
var copy = Object.assign({}, obj1);
var combine = Object.assign(obj1, obj2, obj3);
console.log(copy);
console.log(combine);
console.log(obj1);
// { a: 1 }
// { a: 3 }
// { a: 3 }

function f(x, y=1, z=2) {
return x + y + z;
}
console.log(f(1, 2));
function g(x, y, ...z) {
return (x + y) * z.length;
}
console.log(g(1, 2, 3, 4, 5));
const rest = [3, 4, 5];
console.log([1, 2, param]);
console.log([1, 2, ...param]);
console.log(g(1, 2, 3, ...param));
// 5
// 9
// [ 1, 2, [ 3, 4, 5 ] ]
// [ 1, 2, 3, 4, 5 ]
// 12

function getNewValue(state, action) {
return {
state,
...action.data
}
}

Like what you read? Give Anderson a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.