ES6新特性簡介

ES6新特性簡介

環境安裝

npm install -g babel
npm install -g babel-node  //提供基於node的REPL環境
//建立 .babelrc 文件
{"presets": ["es2015"]}
npm install babel-presets-es2015

箭頭函數和詞法this

箭頭函數的用法相似phython, coffeeScriptjava8php

//expression func body, (僅有1參數 括號可省略)
var odds = evens.map(v => v+1);
var nums = evens.map((v,i) => v + i);

//statement func body
nums.forEach( v => {
    if(v % 5 === 0){
        fives.push(v);
    }
});


//lexical this
var sindy = {
    name: 'Sindy',
    friends: ['nami', 'robin'],
    printFriends() {
        //sindy.printFriends() this指向sindy,
        //forEach迭代函數內部this,跟它定義的上下文this一致
        this.friends.forEach(f=>{
            console.log(this.name + ' knows ' + f);
        });
    }
};

類和繼承

classextend 是一種語法糖,也是基於原型繼承實現的。
class支持 super calls, 實例化,靜態方法和構造函數。java

class關鍵字 聲明類

//class聲明類 內部直接是屬性和方法 不用,分隔。 constructor
class Person{
  constructor(name, age){
    this.name = name;//實例屬性
    this.age = age;
    
  }
 
 sayhi(name){//原型對象的方法
   console.log(this.name+' say hello to ' + name);
 }
 
 static like(){//靜態方法
   console.log('i want to be freedom king');
 }
}

extends關鍵字 聲明繼承

//繼承關鍵字 extends
class Zoro extends Person{

  constructor(fav){
    super('zoro', 18); //constructor中, super引用父類的構造函數

    this.fav = 'keep going';

    // console.log(super); //error 不能直接打印super 
    console.log(super('cici',9),'<--c');

  }
  
  sayhi(){
    // console.log(super); //error 不能直接打印super
    console.log(super.sayhi(),'<--m'); //原型對象的方法中, super引用父類的原型對象
    
    super.sayhi();//調用父類原型對象的方法
  }
}

加強的對象字面量

書寫對象字面量更方便簡潔。 如:foo:foo的簡寫, 函數定義簡寫, 動態屬性名。node

var obj = {
    __proto__: theProtoObj, //設置原型對象
    ['__proto__']: somethingElse, //['__proto__']表示計算的屬性名,不會認爲是設置原型對象, 有時也可避免提前報同名屬性的錯誤
    handler,  // hanlder: handler 的簡寫
    toString(){//相似定義類 命名函數表達式的名稱做爲key
        //super calls
        return 'd' + super.toString(); //super 應該指向 theProtoObj
    },
    ['prop_'+(()=>23)]: 23 //[expression] 中括號表示內部爲屬性名的計算表達式,可實現動態屬性名
}

__proto__屬性在node下都支持,但在瀏覽器環境不必定都支持, chrome是支持的。es6

模板字符串

模板字符串跟php雙引號字符串相似 "hello ,$name",字符串中能夠解析變量和語句, 對於構造字符串是很方便的。chrome

//單行
`this is an alone night`

//多行
`In ES5 this is
not legal`

//變量插值
var name = 'idle', time='today';
var greeting = `hello ${name}, how are you ${time}`;

//不轉義
String.raw`in es5 "\n" is a line-feed`

解構

參數解構 對象解構 數組解構, 解構是一種十分方便的語法特性. 當結構不對應解析失敗時,會對應的返回undefined,不報錯.typescript

//解構賦值
var [a, b] = [1,2]; // a===1, b===2

var {name, age}  = getPerson();

//參數解構
function hello({name: x}){
    console.log('hello, ', x);
}
hello({name: 'alice'});

//解構失敗
var [a] = []; // a===undefined

//提供解構失敗時的默認值
var [a=1] = []; //a===1 

//參數解構失敗的默認值
function r({x,y,w=10,h=20}){
    return x+y+w+h;
}
r({x:1, y:2});

//參數默認值
function f(a, b=10){
    return a+b;
}
f(5);

//rest arguments
function f(x,...y){//剩餘形參
    // y is an array
    return x * y.length
}

f(3, 'hello', true);//6

function f(x,y,z){
    return x+y+z;
}

f(...[2,3,4]); //=>9 剩餘實參

塊級做用域

letconst 聲明的變量和常量都是屬於塊級做用域的.express

function f(){
    let x;
    {
        const x = 'sindy'; //ok 由於塊級做用域
        x = 'foo'; //error 由於x是常量
    }
    x = 'bar'; //在let 以後賦值,沒問題
    let x = 'inner'; //error 重複聲明
}

迭代對象(iterator) 和 for .. of ..

迭代對象容許自定義迭代方式,如:npm

let fibonacci = {
    [Symbol.iterator]() {
        let pre=0, cur=1;
        return {//返回包含next方法的迭代對象(iterator)
            next(){
                [pre, cur] = [cur, pre+cur];
                return {done: false, value: cur}; //iteratorResult
            }
        }
    }
};

for(var n of fibonacci){
    if(n>100){//若無終止條件會一直迭代下去 n應該表明的是每次迭代的結果
        break;
    }
    console.log(n);
}

//typescript風格的iterator接口定義
interface IteratorResult{
    done: boolean,
    value: any
}

interface Iterator {
    next(): IteratorResult //包含next方法,且next()返回IteratorResult類型結果
}

interface Iterable {
    [Symbol.iterator](): Iterator // fibonacci() 執行後返回Iterator
}

生成器generators

function*yield, function*聲明的函數返回一個generator實例. generator是iterator的子類型,它包含本身的thrownext編程

generator能夠實現await風格的異步編程api

//generator版的fibonacci
var fibonacci = {
    [Symbol.iterator]: function*() {//function*聲明
        var pre=0, cur=1;
        for(;;){//不會終止的循環?
            var temp = pre;
            pre = cur;
            cur += pre;
            yield cur;//generator實例每次執行都從yield的地方從新開始?
        }
    }
};

for(var n of fibonacci){
    if(n > 100){
        break;
    }
    console.log(n);
}

//typescript風格的generator接口定義
interface generator extends iterator {
    next(value?: any): IteratorResult; //next方法可帶參數, yield返回參數給next?
    throw(exception: any); 
}

注意 iterator and generator 目前須要polyfill才能使用, 新版的chrome已支持.

unicode的徹底支持

// same as ES5.1
"𠮷".length == 2

// new RegExp behaviour, opt-in ‘u’
"𠮷".match(/./u)[0].length == 2

// new form
"\u{20BB7}" == "𠮷" == "\uD842\uDFB7"

// new String ops
"𠮷".codePointAt(0) == 0x20BB7

// for-of iterates code points
for(var c of "𠮷") {
  console.log(c);
}

模塊(modules)

ES6有不一樣於amdcmd 的模塊風格

//>lib/math.js
export function sum(x,y){
    return x + y;
}

export var fnum = 3.122323;

//>app.js
import * as math from 'lib/math';
console.log(math.sum, math.fnum);

//>other.js
import {fnum, sum} from 'lib/math'; //對象解構賦值
console.log(fnum, sum);

一些額外的特性 export defaultexport *

//>lib/otherMath.js
export * from 'lib/math'; //導出math.js的接口
export var e = 2.323;
export default function(x){
    return Math.exp(x);
}

//>app.js
import exp, {sum , e} from 'lib/otherMath';

模塊導出 export

var name = 'sindy';
var age = 20;

//至關於node  module.exports = {name:name, age:age};
export {name, age};

//至關於module.exports.default = function getName(){..}
export default function getName(){
    return name;
}

模塊導入 import

//import m from './modA';  m === modA.export.default

//import {name, age} from './modA' modA.exports 析構

import getName, {name, age} from './module-e.es';

console.log(name, age);
console.log(getName());

Map , Set, WeakMap, WeakSet

//Sets
var s = new Set();
s.add('hello').add('goodbye').add('hello');//已有則再也不加入
s.size === 2; //true

//Maps
var m = new Map();
m.set('hello', 'good');
m.set(s, 23);
m.get(s) === 23;

//WeakMap
var wm = new WeakMap();
wm.set(s, {extra:24});
vm.size === undefined;

//WeakSet
var ws = new WeakSet();
ws.add({data:12});

proxies

攔截或代理對象的屬性讀寫,函數的調用。

//proxy a normal object
var target = {};//被代理的對象
var handler = {//代理哪些方法
    get: function(reciever, name){//get代理對屬性的訪問
        return `hello, ${name}`;
    }
};
var p = new Proxy(target, handler);
p.world === 'hello, world';

//proxy a function object
var target = function(){ console.log('i am the target'); };
var handler = {
    apply: function(reciever,...args){//代理 target()
        console.log('i am the proxy');
    }
};


//代理的類型
var handler = {
    //target.prop
    get: ...,
    //target.prop = val
    set: ...,
    //prop in target
    has: ...,
    //delete target.prop
    deleteProperty: ...,
    //target(args)
    apply: ...,
    //new target(args)
    constructor: ...,
    //Object.getOwnPropertyDescriptor(target, prop)
    getOwnPropertyDescriptor: ...,
    //Object.defineProperty(target, prop, descriptor)
    defineProperty: ...,
    //Object.getPrototypeOf(target), target.__proto__
    //obj.isPrototypeOf(target), obj2 instanceof target
    getPrototypeOf: ...,
    //Object.setPrototypeOf(target, proto)
    setPrototypeOf: ...,
    //for(var i in target)
    enumerate: ...,
    //Object.keys(target)
    ownKeys: ...,
    //Object.preventExtensions(target)
    preventExtensions: ...,
    //Object.isExtensible(target)
    isExtensible: ...
}

標識符 symbol

(function(){
    //module scope symbol
    var key = Symbol('key');

    function MyClass(privateData){
        this[key] = privateData;
    }
    MyClass.prototype = {
        dostuff: function(){
            ...this[key]..
        }
    };

    typeof key === 'symbol';
})();

var c = new MyClass();
c['key'] === undefined;

內置的子類

Array , DateElement等成爲內置的子類。

class MyArray extends Array{
    constructor(...args){
        super(...args);
    }
}

var arr = new MyArray();
arr[1] = 12;
arr.length === 2;

Math + Number + String + Object API擴展

Number.isInterger(Ifinity); //false
Number.isNaN('NaN'); //false

Math.hypot(3,4); //5

'abcde'.includes('abc');
'abc'.repeat(2);

Array.from(document.querySelectAll('h2')); //return a real array
Array.of(1,2,3); => [1,2,3] 枚舉數組元素的形式 建立數據, 同 new Array(1,2,3); 但沒有僅有1各參數時的歧義
[0,0,0].fill(7,1); //從index==1開始填充7
[1,2,3].findIndex(x=>x==2); //返回使迭代器爲真的元素的索引
['a','b','c'].entries(); //iterator [0,'a'], [1,'b'], [2, 'c']
['a','b','c'].keys(); //iterator 0,1,2
['a','b','c'].values(); //iterator 'a','b','c'

var alice = {name: 'Alice'};
Object.assign(alice, {age: 18}); //相似extend

二進制和八進制字面量

0b111110111 === 503
0o767 === 503

Promises

Promise是一個異步編程的庫,存在於不少其餘的JS庫中

function timeout(duration = 0){
    return new Promise((resolve, reject) => {//返回稍後將被resolve的promise對象
        setTimeout(resolve, duration);//定時resolve這個新new的promise
    });
}

var p = timeout(1000).then(()=>{//promise鏈
    return timeout(2000);
}).then(()=>{
    throw new Error('test');
}).catch(err=>{
    return Promise.all([timeout(100), timeout(200)]);
});

反射API(Reflect API)

var o = {a: 1};
Object.defineProperty(o, 'b', {value:2});
o[Symbol('c')] = 3;

Reflect.ownKeys(o); //['a','b',Symbol(c)]

function C(a,b){
    return this.c = a + b;
}
var instance = Reflect.construct(C, [10,12]);
instance.c === 22;

尾調用 tail calls

防止stack overflow

function factorial(n, acc=1){//階乘計算
    'use strict';
    if(n <= 1){ return acc; }
    return factorail(n-1, n*acc);
}

factorail(10000); //尾調用優化後不會 stack overflow
相關文章
相關標籤/搜索