ES6學習筆記

簡介

  • ECMAScript(ECMA或ES) 是規範, JavaScript的是其規範的實現
  • ECMAScript 2015 = ES2015 ≈ ES6

ECMAScript 的歷史

時間 ECMA JS 解釋
1996.11 ES 1.0 JS穩定 Netscape將JS提交給ECMA組織,ES正式出現
1998.06 ES 2.0 ES2正式發佈
1999.12 ES 3.0 ES3被普遍支持
2007.10 ES 4.0 ES4過於激進,被廢了
2008.07 ES 3.1 4.0退化爲嚴重縮水版的3.1<br/>由於吵得太厲害,因此ES 3.1代號爲Harmony(和諧)
2009.12 ES 5.0 ES 5.0正式發佈<br/>同時公佈了JavaScript.next也就是後來的ES 6.0
2011.06 ES 5.1 ES 5.1成爲了ISO國際標準
2013.03 ES 6.0 ES 6.0草案定稿
2013.12 ES 6.0 ES 6.0草案發布
2015.06 ES 6.0 ES 6.0預計發佈正式版<br/>JavaScript.next開始指向ES 7.0

語法提案批准流程

Stage 0 - Strawman(展現階段)
Stage 1 - Proposal(徵求意見階段)
Stage 2 - Draft(草案階段)
Stage 3 - Candidate(候選人階段)
Stage 4 - Finished(定案階段)

由TC39 委員會批准

Let、const

  • 塊級做用域
  • 不存在變量提高

暫時性死區(temporal dead zone,簡稱 TDZ):在代碼塊內,聲明變量以前,該變量都是不可用的。html

  • 相同做用域內,不容許重複聲明
  • 區別:es6

    • let聲明變量
    • const聲明只讀常量,常量指向的那個內存地址不得改動,且一旦聲明變量,就必須當即初始化。

解構賦值

ES6 容許按照必定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構(Destructuring)。
適用於數組(這裏泛指具備Iterator接口的數據結構)、對象、字符串、數值和布爾值,可設置默認值。ajax

//數組
let [x, y = 'b', z='c'] = ['a', undefined, null];// x='a', y='b' z=null
//對象
let { bar, foo } = { foo: "aaa", bar: "bbb" };//foo = "aaa"; bar = "bbb"
//字符串,先轉爲數組
const [a, b, length : len] = 'ho';//a="h";b= "o";len = 2
//數值與布爾值,先轉爲對象
let {toString: s} = 123;//s = Number.prototype.toString
let {toString: s} = true;//s = Boolean.prototype.toString
  • 若是解構不成功,變量的值就等於undefined
  • 只有當成員嚴格等於undefined,默認值纔會生效
  • 兩邊的結構要一致
  • 結構完當即賦值,結構和賦值不能分開進行
  • 使用於對象時,鍵對鍵,值對值;且大括號不能在行首(會理解成語法塊),可用小括號包裹
  • 解構賦值的規則是,只要等號右邊的值不是對象或數組,就先將其轉爲對象

字符串擴展

查找

  • includes(String):是否找到參數字符串。
  • startsWith(String):是否以參數字符串開頭。
  • endsWith(String):是否以參數字符串結尾。
let s = 'Hello world!';
s.includes('o') // true
//都可接受第二個位置參數

重複

  • repeat(Number)
'x'.repeat(3) // "xxx"

模板字符串

  • 支持變量、表達式、函數調用,容許嵌套
  • 反引號需使用反斜槓轉義
  • trim消除空格和換行
$('#result').append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);
//trim
$('#list').html(`
<ul>
  <li>first</li>
  <li>second</li>
</ul>
`.trim());

數值的擴展

  • Number.isFinite()-只對數值返回true
  • Number.isNaN()-只對NaN返回true
  • Number.isInteger()-只對整數返回true
  • Number.isSafeInteger()-只對安全整數(-2^53到2^53,不含端點)返回true
  • Number.MAX_SAFE_INTEGER,Number.MIN_SAFE_INTEGER安全整數的上下限常量
Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false

Math對象擴展:http://es6.ruanyifeng.com/#do...編程


函數的擴展

  • 參數默認值,建議用於尾參數,不可在函數內再次聲明
function log(x, y = 'World') {}
  • length:從第一個參數到首個指定默認值參數間參數的個數
(function (a, b = 1, c) {}).length // 1
  • rest:獲取函數的多餘參數,須用於尾參數
function add(...values) {}
add(2, 5, 3)
  • name:函數的名字
function f() {}
//或者
var f = function () {};
f.name // "f"

箭頭函數

  • 只有一個參數,可省略參數的小括號,無參數時不可省略
  • 若是隻有一條語句且無return,能夠省略語句塊的大括號
  • 若是隻有一條語句且有return,能夠省略大括號和return,僅有return(即return後無參數)時不可省略
  • 直接返回對象,須使用小括號包裹
let getTempItem = id => ({ id: id, name: "Temp" });
  • 可使用解構賦值,能夠嵌套
const full = ({ first, last }) => first + ' ' + last;
const pipeline = (...funcs) =>
  val => funcs.reduce((a, b) => b(a), val);
  • 注意:json

    • 函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。
    • 不能夠看成構造函數,也就是說,不可使用new命令,不然會拋出一個錯誤。
    • 不可使用arguments對象,該對象在函數體內不存在。若是要用,能夠用 rest 參數代替。
    • 不可使用yield命令,所以箭頭函數不能用做 Generator 函數。

數組的擴展

擴展運算符

用於數組賦值須放在參數的最後一位。數組

console.log(1, ...[2, 3, 4], 5) // 1 2 3 4 5
//複製數組
const a1 = [1, 2];
const a2 = [...a1];// 寫法一
const [...a2] = a1;// 寫法二
//合併數組
const a2 = [3, 4];
[...a1, ...a2] //[1,2,3,4]
//配合解構賦值
const [first, ...rest] = [1, 2, 3, 4, 5];// first= 1;rest= [2, 3, 4, 5]
//字符串
[...'hello'] // [ "h", "e", "l", "l", "o" ]

新增方法

  • Array.from():將數組對象(有length屬性)或可遍歷的對象(包括 ES6 新增的數據結構 Set 和 Map)轉爲真正的數組,接受第二個參數(對每一個元素進行處理,處理值返回數組)。
let arrayLike = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
  • Array.of():將一組值轉換爲數組。
Array.of(3, 11, 8) // [3,11,8]
  • copyWithin(target[必需,替換開始位置,負值爲倒數], start = 0[可選,讀取開始位置,負值爲倒數], end = this.length[可選,讀取結束位置,負值爲倒數]):在當前數組內部,將指定位置的成員複製到其餘位置(會覆蓋原有成員),而後返回當前數組。
[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]
  • find(fn)findIndex(fn):找出第一個符合條件的數組成員。若是無符合條件的成員,返回undefined。
//find方法的回調函數能夠接受三個參數,依次爲當前的值、當前的位置和原數組
[1, 5, 10, 15].find(function(value, index, arr) {
  return value > 9;
}) // 10
  • fill(text[必需,填充內容],start = 0[可選,開始位置,負值爲倒數], end = this.length[可選,結束位置,負值爲倒數]): 使用給定值,填充一個數組。
['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']
  • includes(text[必需,內容],start = 0[可選,搜索開始位置,負值爲倒數], end = this.length[可選,搜索結束位置,負值爲倒數]):搜索數組是否包含給定的值。
[1, 2, 3].includes(3, -1); // true

對象的擴展

  • 簡潔表示:對象的key和value同樣時,能夠省略key,方法可省略function
const foo = 'bar';
const baz = {
    foo,
   method() {
    return "Hello!";
  }
}
  • 屬性名錶達式: 不能使用簡潔表示
let propKey = 'foo';

let obj = {
  [propKey]: true,
  ['a' + 'bc']: 123
}
  • Object.is(): 判斷兩值是否相等
//和===的區別
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
  • Object.assign(target[目標對象], source1, source2,...): 將源對象全部可枚舉屬性複製合併到目標對象。
const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
  • Object.assign方法實行的是淺拷貝,而不是深拷貝。也就是說,若是源對象某個屬性的值是對象,那麼目標對象拷貝獲得的是這個對象的引用。
  • 遇到同名屬性,Object.assign的處理方法是後面替換前面的。
  • Object.assign能夠用來處理數組,可是會把數組視爲對象。
  • Object.assign只能進行值的複製,若是要複製的值是一個取值函數,那麼將求值後再複製。

Set和Map數據結構

Set(集合)

集合:集合是由一組無序且惟一(即不能重複)的項組成的,能夠想象成集合是一個既沒有重複元素,也沒有順序概念的數組promise

基本用法

ES6 提供了新的數據結構 Set。它相似於數組,可是成員的值都是惟一的,沒有重複的值。
Set 自己是一個構造函數,用來生成 Set 數據結構。瀏覽器

const s = new Set();

[2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));

for (let i of s) {
  console.log(i);
}
// 2 3 5 4
// 去除數組的重複成員
const set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]

向 Set 加入值的時候,不會發生類型轉換。安全

屬性和方法

Set 結構的實例有如下屬性。服務器

  • size:返回Set實例的成員總數。
實例操做方法(用於操做數據)
  • add(value):添加某個值,返回 Set 結構自己。
  • delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。
  • has(value):返回一個布爾值,表示該值是否爲Set的成員。
  • clear():清除全部成員,沒有返回值。
s.add(1).add(2).add(2);
// 注意2被加入了兩次

s.size // 2

s.has(1) // true
s.has(2) // true
s.has(3) // false

s.delete(2);
s.has(2) // false
遍歷方法(用於遍歷成員)

Set 結構的實例有四個遍歷方法,能夠用於遍歷成員。

  • keys():返回鍵名的遍歷器
  • values():返回鍵值的遍歷器
  • entries():返回鍵值對的遍歷器
  • forEach():使用回調函數遍歷每一個成員

須要特別指出的是,Set的遍歷順序就是插入順序。這個特性有時很是有用,好比使用 Set 保存一個回調函數列表,調用時就能保證按照添加順序調用。

let set = new Set(['red', 'green', 'blue']);

for (let item of set.keys()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.values()) {
  console.log(item);
}
// red
// green
// blue

for (let item of set.entries()) {
  console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

WeakSet

WeakSet 結構與 Set 相似,也是不重複的值的集合。可是,它與 Set 有兩個區別。

首先,WeakSet 的成員只能是對象,而不能是其餘類型的值;

WeakSet 中的對象都是弱引用,即垃圾回收機制不考慮 WeakSet 對該對象的引用,也就是說,若是其餘對象都再也不引用該對象,那麼垃圾回收機制會自動回收該對象所佔用的內存。

語法

WeakSet 是一個構造函數,可使用new命令,建立 WeakSet 數據結構。

const a = [[1, 2], [3, 4]];
const ws = new WeakSet(a);
// WeakSet {[1, 2], [3, 4]}

方法

WeakSet 結構有如下三個方法。

  • add(value):向 WeakSet 實例添加一個新成員。
  • delete(value):清除 WeakSet 實例的指定成員。
  • has(value):返回一個布爾值,表示某個值是否在 WeakSet 實例之中。

Map(字典)

相似對象,惟一的區別是key的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵。主要用於數據存儲

const map = new Map([
  ['name', '張三'],
  ['title', 'Author']
]);

map.size // 2
map.has('name') // true
map.get('name') // "張三"
map.has('title') // true
map.get('title') // "Author"

屬性和方法

  • size:屬性返回 Map 結構的成員總數。
  • set(key, value):

set方法設置鍵名key對應的鍵值爲value,而後返回整個 Map 結構。若是key已經有值,則鍵值會被更新,不然就新生成該鍵。

const m = new Map();

m.set('edition', 6)        // 鍵是字符串
m.set(262, 'standard')     // 鍵是數值
m.set(undefined, 'nah')    // 鍵是 undefined
//或者
let map = new Map()
  .set(1, 'a')
  .set(2, 'b')
  .set(3, 'c');
  • get(key):

get方法讀取key對應的鍵值,若是找不到key,返回undefined。

  • has(key):

has方法返回一個布爾值,表示某個鍵是否在當前 Map 對象之中

  • delete(key):

delete方法刪除某個鍵,返回true。若是刪除失敗,返回false。

  • clear():

clear方法清除全部成員,沒有返回值。

遍歷:

提供三個遍歷器生成函數和一個遍歷方法。Map 的遍歷順序就是插入順序

  • keys():返回鍵名的遍歷器。
  • values():返回鍵值的遍歷器。
  • entries():返回全部成員的遍歷器。
  • forEach():遍歷 Map 的全部成員。

數據結構轉換

  • Map 轉爲數組
const myMap = new Map()
  .set(true, 7)
  .set({foo: 3}, ['abc']);
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]
  • 數組 轉爲 Map
new Map([
  [true, 7],
  [{foo: 3}, ['abc']]
])
// Map {
//   true => 7,
//   Object {foo: 3} => ['abc']
// }
  • Map 轉爲對象
function strMapToObj(strMap) {
  let obj = Object.create(null);
  for (let [k,v] of strMap) {
    obj[k] = v;
  }
  return obj;
}

const myMap = new Map()
  .set('yes', true)
  .set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }
  • 對象轉爲 Map
function objToStrMap(obj) {
  let strMap = new Map();
  for (let k of Object.keys(obj)) {
    strMap.set(k, obj[k]);
  }
  return strMap;
}

objToStrMap({yes: true, no: false})
// Map {"yes" => true, "no" => false}
  • Map 轉爲 JSON

Map 轉爲 JSON 要區分兩種狀況。一種狀況是,Map 的鍵名都是字符串,這時能夠選擇轉爲對象 JSON。

function strMapToJson(strMap) {
  return JSON.stringify(strMapToObj(strMap));
}

let myMap = new Map().set('yes', true).set('no', false);
strMapToJson(myMap)
// '{"yes":true,"no":false}'

另外一種狀況是,Map 的鍵名有非字符串,這時能夠選擇轉爲數組 JSON。

function mapToArrayJson(map) {
  return JSON.stringify([...map]);
}

let myMap = new Map().set(true, 7).set({foo: 3}, ['abc']);
mapToArrayJson(myMap)
// '[[true,7],[{"foo":3},["abc"]]]'
  • JSON 轉爲 Map

JSON 轉爲 Map,正常狀況下,全部鍵名都是字符串。

function jsonToStrMap(jsonStr) {
  return objToStrMap(JSON.parse(jsonStr));
}

jsonToStrMap('{"yes": true, "no": false}')
// Map {'yes' => true, 'no' => false}

可是,有一種特殊狀況,整個 JSON 就是一個數組,且每一個數組成員自己,又是一個有兩個成員的數組。這時,它能夠一一對應地轉爲 Map。這每每是數組轉爲 JSON 的逆操做。

function jsonToMap(jsonStr) {
  return new Map(JSON.parse(jsonStr));
}

jsonToMap('[[true,7],[{"foo":3},["abc"]]]')
// Map {true => 7, Object {foo: 3} => ['abc']}

WeakMap

WeakMap結構與Map結構相似,也是用於生成鍵值對的集合。
區別:

  • WeakMap只接受對象做爲鍵名(null除外),不接受其餘類型的值做爲鍵名。
  • WeakMap的鍵名所指向的對象,不計入垃圾回收機制。

區別

集合又和字典有什麼區別呢:

  • 共同點:集合、字典能夠存儲不重複的值
  • 不一樣點:集合是以[值,值]的形式存儲元素,字典是以[鍵,值]的形式存儲

Promise對象

Promise 是異步編程的一種解決方案,比傳統的解決方案(回調函數和事件),更合理和更強大。

  • 特色:

    • 對象的狀態[pending(進行中)、fulfilled(已成功)和rejected(已失敗)]不受外界影響
    • 一旦狀態改變,就不會再變,任什麼時候候獲得的都是這個結果
const promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 異步操做成功 */){
    resolve(value); //將Promise對象的狀態從「未完成」變爲「成功」,並將異步操做的結果,做爲參數傳遞出去
  } else {
    reject(error); //將Promise對象的狀態從「未完成」變爲「失敗」,並將異步操做報出的錯誤,做爲參數傳遞出去
  }
});
//調用
promise.then(value=> {
  // success
}, error=> { //可選
  // failure
});
//或者
promise.then(value => {
  // success
}).catch(error => {
  // failure
});
  • Promise.all([p1, p2, ...]): 將多個 Promise 包裝成一個新的 Promise ,狀態和值取決於裏面的實例(fulfilled:需均成功,返回包含每一個實例返回值的數組;rejected:至少一個失敗,返回第一個失敗的實例返回值)
  • Promise.race([p1, p2, ...]): 將多個 Promise 包裝成一個新的 Promise,狀態和參數均由裏面第一個改變的狀態的實例決定
  • Promise.resolve():簡寫,將現有對象轉爲 狀態爲fulfilled的Promise 對象。
Promise.resolve('foo')
// 等價於
new Promise(resolve => resolve('foo'))
  • Promise.reject():簡寫,將現有對象轉爲 狀態爲rejected的Promise 對象。
const p = Promise.reject('出錯了');
// 等同於
const p = new Promise((resolve, reject) => reject('出錯了'))

Iterator(遍歷器)

概念

數據集合:主要是Array,Object,Map,Set。
遍歷器(Iterator)爲上述數據集合提供了統一的訪問機制。

Iterator 的做用有三個:
  • 一是爲各類數據結構,提供一個統一的、簡便的訪問接口;
  • 二是使得數據結構的成員可以按某種次序排列;
  • 三是 ES6 創造了一種新的遍歷命令for...of循環,Iterator 接口主要供for...of消費。

for...of 循環

const arr = ['red', 'green', 'blue'];

for(let v of arr) {
  console.log(v); // red green blue
}
區別:
  • for...in遍歷鍵名,for...of遍歷鍵值
var arr = ['a', 'b', 'c', 'd'];

for (let a in arr) {
  console.log(a); // 0 1 2 3
}

for (let a of arr) {
  console.log(a); // a b c d
}
  • for...of能夠配合break、continue和return使用
for (var n of fibonacci) {
  if (n > 1000)
    break;
  console.log(n);
}

Generator

概念

Generator 函數是 ES6 提供的一種異步編程解決方案。
Generator 函數是一個狀態機,封裝了多個內部狀態。

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

Generator 函數的調用方法與普通函數同樣,也是在函數名後面加上一對圓括號。不一樣的是,調用 Generator 函數後,該函數並不執行,必須調用next()纔會執行,返回的也不是函數運行結果,而是一個指向內部狀態的指針對象(yield)。

yield 表達式

遍歷器對象的next方法的運行邏輯以下。

  • (1)遇到yield表達式,就暫停執行後面的操做,並將緊跟在yield後面的那個表達式的值,做爲返回的對象的value屬性值。
  • (2)下一次調用next方法時,再繼續往下執行,直到遇到下一個yield表達式。
  • (3)若是沒有再遇到新的yield表達式,就一直運行到函數結束,直到return語句爲止,並將return語句後面的表達式的值,做爲返回的對象的value屬性值。
  • (4)若是該函數沒有return語句,則返回的對象的value屬性值爲undefined。
  • yield其實是兩個動做的合體:丟東西出去->等東西進來;

每次next()都會跑到yield丟東西出來的那個步驟

//輸入輸出:yield右邊爲輸出(next返回值的value,最後一次由return返回),左邊爲輸入(接受的是next的參數,第一次由函數參數傳入),
function * input(){
    let array = [], i = 4;
    while(i) {
        array.push(yield array);
        i --;
    }
}

var gen = input();
console.log(gen.next("西")) // { value: [], done: false }
console.log(gen.next("部")) // { value: [ '部' ], done: false }
console.log(gen.next("世")) // { value: [ '部', '世' ], done: false }
console.log(gen.next("界")) // { value: [ '部', '世', '界' ], done: false }

next 方法的參數

yield表達式自己沒有返回值,或者說老是返回undefined。next方法能夠帶一個參數,該參數就會被看成上一個yield表達式的返回值。

for...of 循環

for...of循環能夠自動遍歷 Generator 函數時生成的Iterator對象,且此時再也不須要調用next方法。

function* foo() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
  return 6;
}

for (let v of foo()) {
  console.log(v);
}
// 1 2 3 4 5

next()、throw()、return() 的共同點

next()、throw()、return()這三個方法本質上是同一件事,能夠放在一塊兒理解。它們的做用都是讓 Generator 函數恢復執行,而且使用不一樣的語句替換yield表達式。

  • next()是將yield表達式替換成一個值。
const g = function* (x, y) {
  let result = yield x + y;
  return result;
};

const gen = g(1, 2);
gen.next(); // Object {value: 3, done: false}

gen.next(1); // Object {value: 1, done: true}
// 至關於將 let result = yield x + y
// 替換成 let result = 1;
  • throw()是將yield表達式替換成一個throw語句。
gen.throw(new Error('出錯了')); // Uncaught Error: 出錯了
// 至關於將 let result = yield x + y
// 替換成 let result = throw(new Error('出錯了'));
  • return()是將yield表達式替換成一個return語句。
gen.return(2); // Object {value: 2, done: true}
// 至關於將 let result = yield x + y
// 替換成 let result = return 2;

yield* 表達式

在 Generator 函數內部,調用另外一個 Generator 函數

function* bar() {
  yield 'x';
  yield* foo();
  yield 'y';
}

// 等同於
function* bar() {
  yield 'x';
  yield 'a';
  yield 'b';
  yield 'y';
}

// 等同於
function* bar() {
  yield 'x';
  for (let v of foo()) {
    yield v;
  }
  yield 'y';
}

for (let v of bar()){
  console.log(v);
}
// "x"
// "a"
// "b"
// "y"

做爲對象屬性的 Generator 函數

let obj = {
  * myGeneratorMethod() {
    ···
  }
};
//等價於
let obj = {
  myGeneratorMethod: function* () {
    // ···
  }
};

應用

  • ajax
function* main() {
  var result = yield request("http://some.url");
  var resp = JSON.parse(result);
    console.log(resp.value);
}

function request(url) {
  makeAjaxCall(url, function(response){
    it.next(response);
  });
}

var it = main();
it.next();

更多Generator 函數的異步應用:http://es6.ruanyifeng.com/#do...

http://jsfiddle.net/Yoghurts/...
ES7引入 async await,使其更加好用

利用ES6中的Generator實現併發編程

參考資料

ES6實現

// 暫停
function sleep(numberMillis) {
    var now = new Date();
    var exitTime = now.getTime() + numberMillis;
    while (true) {
        now = new Date();
        if (now.getTime() > exitTime){
            return;
        }
    }
}

// 消費者
function* consumer(name) {
    console.log(`${name}準備吃包子啦!`);
    while (true) {
        var baozi = yield;
        baozi += 1;
        console.log(`第${baozi}個包子來了,被分紅了兩份,一份被${name}吃了!`);
    }
}

// 生產者
function producer(name) {
    c1 = consumer('A');
    c2 = consumer('B');
    console.log(`${name}:我開始準備作包子了!`);
    c1.next();
    c2.next();
    for (let i = 0; i < 10; i++) {
        sleep(1000);
        c1.next(i);
        c2.next(i);
    }
}

// 小明開始生產包子,A和B同時開始吃包子
producer('小明')

運行結果

小明:我開始準備作包子了!
A準備吃包子啦!
B準備吃包子啦!
第1個包子來了,被分紅了兩份,一份被A吃了!
第1個包子來了,被分紅了兩份,一份被B吃了!
第2個包子來了,被分紅了兩份,一份被A吃了!
第2個包子來了,被分紅了兩份,一份被B吃了!
第3個包子來了,被分紅了兩份,一份被A吃了!
第3個包子來了,被分紅了兩份,一份被B吃了!
第4個包子來了,被分紅了兩份,一份被A吃了!
第4個包子來了,被分紅了兩份,一份被B吃了!
第5個包子來了,被分紅了兩份,一份被A吃了!
第5個包子來了,被分紅了兩份,一份被B吃了!
第6個包子來了,被分紅了兩份,一份被A吃了!
第6個包子來了,被分紅了兩份,一份被B吃了!
第7個包子來了,被分紅了兩份,一份被A吃了!
第7個包子來了,被分紅了兩份,一份被B吃了!
第8個包子來了,被分紅了兩份,一份被A吃了!
第8個包子來了,被分紅了兩份,一份被B吃了!
第9個包子來了,被分紅了兩份,一份被A吃了!
第9個包子來了,被分紅了兩份,一份被B吃了!
第10個包子來了,被分紅了兩份,一份被A吃了!
第10個包子來了,被分紅了兩份,一份被B吃了!

Class

定義類

//之前
function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);

ES6 的class能夠看做只是一個語法糖,它的絕大部分功能,ES5 均可以作到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。

//es6
class Point {
//構造方法
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}
var p = new Point(1, 2);

繼承類

class Point {
}

class ColorPoint extends Point {
}

module

簡介

在 ES6 以前,社區制定了一些模塊加載方案,最主要的有 CommonJS 和 AMD 兩種。前者用於服務器,後者用於瀏覽器。ES6 在語言標準的層面上,實現了模塊功能,並且實現得至關簡單,徹底能夠取代 CommonJS 和 AMD 規範,成爲瀏覽器和服務器通用的模塊解決方案。

嚴格模式

ES6 的模塊自動採用嚴格模式,無論你有沒有在模塊頭部加上"use strict";

嚴格模式主要有如下限制:

  • 變量必須聲明後再使用
  • 函數的參數不能有同名屬性,不然報錯
  • 不能使用with語句
  • 不能對只讀屬性賦值,不然報錯
  • 不能使用前綴 0 表示八進制數,不然報錯
  • 不能刪除不可刪除的屬性,不然報錯
  • 不能刪除變量delete prop,會報錯,只能刪除屬性delete global[prop]
  • eval不會在它的外層做用域引入變量
  • eval和arguments不能被從新賦值
  • arguments不會自動反映函數參數的變化
  • 不能使用arguments.callee
  • 不能使用arguments.caller
  • 禁止this指向全局對象
  • 不能使用fn.caller和fn.arguments獲取函數調用的堆棧
  • 增長了保留字(好比protected、static和interface)

export 命令

定義模塊的對外接口。
一個模塊就是一個獨立的文件。該文件內部的全部變量,外部沒法獲取。若是你但願外部可以讀取模塊內部的某個變量,就必須使用export關鍵字輸出該變量。
如下是幾種用法:

//------輸出變量------
export var firstName = 'Michael';
export var lastName = 'Jackson';
//等價於
var firstName = 'Michael';
export {firstName}; //推薦,能清除知道輸出了哪些變量
//------輸出函數或類------
export function multiply(x, y) {
  return x * y;
};
//------輸出並as重命名------
var v1 = 'Michael';
function v2() { ... }
export {
  v1 as streamV1,
  v2 as streamV2
};
//------輸出default------
export default function () { ... }

注意:export default在一個模塊中只能有一個。

import 命令

使用export命令定義了模塊的對外接口之後,其餘 JS 文件就能夠經過import命令加載這個模塊。
如下是幾種用法,必須和上面的export對應:

//------加載變量、函數或類------
import {firstName, lastName} from './profile.js';
//------加載並as重命名------
import { lastName as surname } from './profile.js';
//------加載有default輸出的模塊------
import v1 from './profile.js';
//------執行所加載的模塊------
import 'lodash';
//------加載模塊全部輸出------
import  * as surname from './profile.js';

複合寫法

若是在一個模塊之中,先輸入後輸出同一個模塊,import語句能夠與export語句寫在一塊兒。

export { foo, bar } from 'my_module';

// 等同於
import { foo, bar } from 'my_module';
export { foo, bar };

Symbol

原始數據類型Symbol,表示獨一無二的值。

let s = Symbol();

typeof s
// "symbol"

Symbol函數能夠接受一個字符串做爲參數,表示對 Symbol 實例的描述,主要是爲了在控制檯顯示,或者轉爲字符串時,比較容易區分。

let s1 = Symbol('foo');
let s2 = Symbol('bar');

s1 // Symbol(foo)
s2 // Symbol(bar)

s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(bar)"

Proxy

代理器(攔截器),Proxy 能夠理解成,在目標對象以前架設一層「攔截」,外界對該對象的訪問,都必須先經過這層攔截,所以提供了一種機制,能夠對外界的訪問進行過濾和改寫。

var proxy = new Proxy(target, handler);
  • target參數表示所要攔截的目標對象
  • handler參數也是一個對象,用來定製攔截行爲。
var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`getting ${key}!`);
    return target.key;
  },
  set: function (target, key, value, receiver) {
    console.log(`setting ${key}!`);
    return target.key=value;
  }
});
相關文章
相關標籤/搜索