ES6簡單總結(jié)(搭配簡單的講解和小案例)

在學習es6的過程中,為了方便自己復習,以及查看缀皱,對api做了一個極簡用例介紹。如有錯誤多多指正动猬。

一 let和const

1.let

(1)一個大括號就是一個塊級作用域啤斗,let聲明的變量只在自己作用域有效;
(2)es6強制開啟嚴格模式赁咙,變量未聲明不能引用钮莲,所以會報 Uncaught ReferenceError

function test() {
  for (let i = 1; i < 3; i++) {
    console.log(i)
  }
  console.log(i);  // Uncaught ReferenceError: i is not defined
}
test();

(3)let不能重復聲明

function test() {
  let a = 1; 
  let a = 2;
}
test();

(4)let不存在變量提升(這個地方有問題)

// var 的情況
console.log(a); // 輸出undefined
var a = 2;

// let 的情況
console.log(b); // 報錯ReferenceError
let b = 2;

2.const

(1)const聲明之后必須賦值,否則會編譯不通過彼水;
(2)const聲明的值不允許修改崔拥;

const PI = 3.14;
// PI = 2;  
// const PI;
console.log(PI);

(3)const如果是對象的話,可以向?qū)ο笾刑砑訉傩苑锔玻部梢孕薷腶的屬性链瓦;json是指向內(nèi)存地址的一個指針,指針的指向不變盯桦,但是那個被json指針所指向的內(nèi)存地址所存儲的內(nèi)容是可以變化的慈俯;

const json = {
  a: 2
}
json.a = 3;
json.b = 3;
console.log(json.a)   //3
console.log(json.b)   //3

二 解構(gòu)賦值

1.基本用法

先上兩個例子了解什么是解構(gòu)賦值

{
  let a, b, rest;
  [a, b, rest] = [1, 2];
  console.log(a, b, rest);   //1 2 undefined
}
{
  let a, b, rest;
  [a, b, ...rest] = [1, 2, 3, 4, 5, 6, 7];
  console.log(a, b, rest);   //1 2 [3, 4, 5, 6, 7]
}

2.對象的解構(gòu)賦值

{
  let a, b;
  ({ a, b } = { a: 1, b: 2 });  //a,b 順序不影響其結(jié)構(gòu)結(jié)果
  console.log(a, b); // 1 2
}

3.默認值

{
  let a, b, rest;
  [a, b, rest = 3] = [1, 2];
console.log(a, b, rest); // 1 2 3
}

4.實際應(yīng)用

變量的交換

{
  let a = 1;
  let b = 2;
  [a, b] = [b, a];
  console.log(a, b);  //2 1
}

接收函數(shù)返回的值

{
  function f() {
    return [12, 13];
  }
  let a, b;
  [a, b] = f();
  console.log(a, b); //12 13
}

{
  function f() {
    return [12, 13, 14, 15, 16];
  }
  let a, b;
  [a, , , b] = f();  //函數(shù)返回多個值拥峦,可以選擇性的接收對應(yīng)的值
  console.log(a, b); // 12 16
}

{
  function f() {
    return [12, 13, 14, 15, 16];
  }
  let a, b;
  [a, , ...b] = f();  //取出對應(yīng)的值贴膘,其他的值可以直接賦值給數(shù)據(jù)
  console.log(a, b); // 12 [14, 15, 16]
}

5.對象的解構(gòu)賦值的應(yīng)用

{
  let o = { p: 42, q: true };
  let { p, q } = o;
  console.log(p, q); //42 true
}

{
  let { a = 10, b = 11 } = { a: 3 }  // 對象的默認值更改
  console.log(a,b); // 3, 11
}

6.解構(gòu)賦值的簡單應(yīng)用舉例

{
  let metaData = {
    title: 'abc',
    test: [{
      title: 'gao',
      desc: 'description'
    }]
  }

  let { title: esTitle, test: [{ title: cnTitle }] } = metaData;
  console.log(esTitle, cnTitle);
}

三 正則的擴展

1.構(gòu)造函數(shù)來創(chuàng)建正則

{
  let regex1 = new RegExp('xyz', 'i');
  let regex2 = new RegExp(/xyz/i);
  console.log(regex1.test('xyz123'), regex2.test('xyz123')); // true true


  let regex3 = new RegExp(/xyz/ig, 'i'); // 后面的修飾符會把前面的修飾符給覆蓋掉
  console.log(regex3.flags);  // es6新增的,用來獲取正則表達式的修飾符
}

2.g修飾符和y修飾符

y修飾符的作用與g修飾符類似略号,也是全局匹配刑峡,后一次匹配都從上一次匹配成功的下一個位置開始洋闽。不同之處在于,g修飾符只要剩余位置中存在匹配就可突梦,而y修飾符確保匹配必須從剩余的第一個位置開始诫舅。

{
  let s = 'bbb_bb_b';
  let a1 = /b+/g; // g只要匹配到都算
  let a2 = /b+/y; // y必須是下一個開始的字母開始匹配

  console.log('one', a1.exec(s), a2.exec(s)); // g修飾符匹配到都可以,y修飾符必須從第一個開始匹配阳似,如果一第個不是b則會輸出null
  console.log('two', a1.exec(s), a2.exec(s)); // 第二次匹配骚勘,g修飾符會只要匹配到都可以,y修飾符必須從緊鄰的下一個字符開始匹配
  
  console.log(a1.sticky, a2.sticky); // 判斷是否開啟了y修飾符   false true
}

one和two的輸出結(jié)果
[圖片上傳失敗...(image-6b6ca8-1517308143359)]

3.u修飾符(unicode)

ES6 對正則表達式添加了u修飾符撮奏,含義為“Unicode模式”俏讹,用來正確處理大于\uFFFF的 Unicode 字符。

{
  console.log('u-1', /^\uD83D/.test('\uD83D\uDC2A')); // 不加u把后面的四個字節(jié)當成兩個字符
  console.log('u-2', /^\uD83D/u.test('\uD83D\uDC2A')); // 加u把后面的4個字節(jié)當作一個字符

  console.log(/\u{61}/.test('a'));  // false 大括號括起來代表一個unicode字符畜吊,所以必須加u才能識別
  console.log(/\u{61}/u.test('a')); // true

  console.log(`\u{20BB7}`);
  let s = '??';
  console.log('u-1', /^.$/.test(s));  //false 字符串大于兩個字節(jié)泽疆,必須加u修飾符才能匹配到
  console.log('u-2', /^.$/u.test(s)); //true

  console.log('test-1', /??{2}/.test('????')); // false
  console.log('test-2', /??{2}/u.test('????')); // true
}

四 字符串擴展

1.unicode的表示方法

{
  console.log('a', '\u0061'); // a a
  console.log('s', '\u20BB7'); // s ?7  把前兩個字節(jié)當作一個整體
  console.log('s', '\u{20BB7}'); // s ??  unicode編碼用{}可以正常識別
}

2.codePointAt和charCodeAt的對比

對于4個字節(jié)的字符,JavaScript不能正確處理玲献,字符串長度會誤判為2殉疼,而且charAt方法無法讀取整個字符,charCodeAt方法只能分別返回前兩個字節(jié)和后兩個字節(jié)的值捌年。ES6提供了codePointAt方法瓢娜,能夠正確處理4個字節(jié)儲存的字符,返回一個字符的碼點礼预。

{
   let s = '??';
   console.log(s.length);  // 2
   console.log('0', s.charAt(0));  // 0 ?   //es5未對多個字節(jié)的字符做處理
   console.log('1', s.charAt(1));  // 1 ?
   console.log('at0', s.charCodeAt(0));  //at0 55362
   console.log('at1', s.charCodeAt(1));  //at1 57271
   
   let s1 = '??a';
   console.log('length', s1.length); // 3
   console.log('code0', s1.codePointAt(0)); // code0 134071
   console.log('code0', s1.codePointAt(0).toString(16));  // code0 es6會自動把多個字節(jié)的字符當作一個整體來處理 
   console.log('code1', s1.codePointAt(1)); // code1 57271
   console.log('code2', s1.codePointAt(2)); // code2 97
}

3.fromCharCode和fromCodePoint

ES5提供String.fromCharCode方法眠砾,用于從碼點返回對應(yīng)字符,但是這個方法不能識別Unicode編號大于0xFFFF托酸。ES6提供了String.fromCodePoint方法褒颈,可以識別大于0xFFFF的字符,彌補了String.fromCharCode方法的不足励堡。在作用上谷丸,正好與codePointAt方法相反。注意应结,fromCodePoint方法定義在String對象上刨疼,而codePointAt方法定義在字符串的實例對象上。

{
  console.log(String.fromCharCode('0x20bb7'));  //?
  console.log(String.fromCodePoint('0x20bb7'))  //??
}

4.字符串遍歷器

{
  // es5
  let str = '\u{20bb7}abc';
  for (let i = 0; i < str.length; i++) {
    console.log('es5', str[i]);
    
    //? ? a b c   
  }
  //es6
  for (let code of str) {
    console.log('es6', code);
    
    // ?? a b c
  }
}

5.一些常用的字符串a(chǎn)pi

{
  let str = 'string';
  console.log('includes', str.includes('c'));  // 判斷是否包含  false
  console.log('start', str.startsWith('s'));   // 以什么開頭  true
  console.log('end', str.endsWith('ng'));   // 以什么結(jié)尾   true
  console.log('repeat', str.repeat(2));     // 字符串重復兩次  stringstring
}

ES6 引入了字符串補全長度的功能摊趾。如果某個字符串不夠指定長度币狠,會在頭部或尾部補全。padStart()用于頭部補全砾层,padEnd()用于尾部補全。如果原字符串的長度贱案,等于或大于指定的最小長度肛炮,則返回原字符串止吐。如果用來補全的字符串與原字符串,兩者的長度之和超過了指定的最小長度侨糟,則會截去超出位數(shù)的補全字符串碍扔。

{
    console.log('1'.padStart(2,'0')); // 01
    console.log('1'.padEnd(2,'0')); // 10
}

6.模板字符串

{
  let name = "List";
  let info = "hello world";
  let m = `i am ${name} ${info}`;
  console.log(m);  //i am List hello world
}

7.標簽?zāi)0?/h2>
{
  let user = {
    name:'list',
    info:'hello world'
  }

  function fn(s,v1,v2){
    console.log(s,v1,v2);
    return s+v1+v2;
  }

  console.log(fn`i am ${user.name} ${user.info}`)  // ``符號相當于一個函數(shù)的參數(shù)fn(i am ${user.name} ${user.info});
}

輸出結(jié)果
[圖片上傳失敗...(image-96cb9b-1517308143359)]

8.String.row API

ES6還為原生的String對象,提供了一個raw方法秕重。String.raw方法不同,往往用來充當模板字符串的處理函數(shù),返回一個斜杠都被轉(zhuǎn)義(即斜杠前面再加一個斜杠)的字符串溶耘,對應(yīng)于替換變量后的模板字符串二拐。

{
  console.log('raw '+String.raw`hi\n${1+2}`)
  console.log('noRaw '+`hi\n${1+2}`)
}

輸出結(jié)果
[圖片上傳失敗...(image-fd3999-1517308143359)]

五 數(shù)值擴展

1.二進制八進制表示法

從 ES5 開始,在嚴格模式之中凳兵,八進制就不再允許使用前綴0表示百新,ES6進一步明確,要使用前綴0o表示庐扫。如果要將0b和0o前綴的字符串數(shù)值轉(zhuǎn)為十進制饭望,要使用Number方法。

{
  console.log('B',0b11010101010);  //二進制表示形庭,b大小寫都可以
  console.log('O',0O1237637236);  // 八進制表示法
}

2.Number.isFinite()和Number.isNaN()

Number.isFinite()用來判斷數(shù)字是否有限(無盡小數(shù))铅辞,Number.isNaN()來判斷一個數(shù)是不是小數(shù)

{
  console.log('15',isFinite(15));    //true
  console.log('NaN',isFinite(NaN));  //false
  console.log('1/0',isFinite(1/0));  //false
  console.log('isNaN',Number.isNaN(15)); // false
  console.log('isNaN',Number.isNaN(NaN));  // true
}

3.Number.isInteger

Number.isInteger用來判斷一個數(shù)是不是整數(shù)

{
  console.log('13',Number.isInteger(13));      // true
  console.log('13.0',Number.isInteger(13.0));  // true 
  console.log('13.1',Number.isInteger(13.1));  //false
  console.log('13',Number.isInteger('13'));    // false
}

4.Number.MAX_SAFE_INTEGER,Number.MIN_SFAE_INTEGER和isSafeInterger

Number.MAX_SAFE_INTEGER,Number.MIN_SFAE_INTEGER表示js可以準確表示的值的范圍,isSafeInterger用來判斷這個值是否在安全范圍內(nèi)萨醒。

{
  console.log(Number.MAX_SAFE_INTEGER,Number.MIN_SFAE_INTEGER);
  console.log('15',Number.isSafeInteger(15));
  console.log('9999999999999999999999',Number.isSafeInteger(9999999999999999999999));
}

5.Math.trunc和Math.sign

Math.trunc方法用于去除一個數(shù)的小數(shù)部分斟珊,返回整數(shù)部分。Math.sign方法用來判斷一個數(shù)到底是正數(shù)验靡、負數(shù)倍宾、還是零。對于非數(shù)值胜嗓,會先將其轉(zhuǎn)換為數(shù)值高职。

{
  console.log('4.1',Math.trunc(4.1));   //4
  console.log('4.9',Math.trunc(4.9));   //4
}
{
  console.log('-5',Math.sign(-5))    //-1
  console.log('5',Math.sign(5))      //+1
  console.log('0',Math.sign(0))      //0
  console.log('50',Math.sign(50))    //+1
  console.log('NaN',Math.sign(NaN))  //NaN
} 

6.cbrt

cbrt用來計算一個數(shù)的開方

{
  console.log('-1',cbrt(-1));   //-1
  console.log('8',cbrt(8));     //2
}

六 數(shù)組擴展

1. Array.of

Array.of方法用于將一組值,轉(zhuǎn)換為數(shù)組,這個方法的主要目的辞州,是彌補數(shù)組構(gòu)造函數(shù)Array()的不足怔锌。因為參數(shù)個數(shù)的不同,會導致Array()的行為有差異变过。

{
  let arr = Array.of(1,2,3,4);
  console.log('arr=',arr);  // arr= [1, 2, 3, 4]

  let emptyArr = Array.of();
  console.log(emptyArr);  // []

  //與Array方法對比
  Array() // []
  Array(3) // [, , ,]
  Array(3, 11, 8) // [3, 11, 8]
}

2.Array.from

Array.from方法用于將兩類對象轉(zhuǎn)為真正的數(shù)組:類似數(shù)組的對象和可遍歷的對象(包括ES6新增的數(shù)據(jù)結(jié)構(gòu)Set和Map)埃元。

<p>你好</p>
<p>我好</p>
<p>大家好</p>

{
  let p = document.querySelectorAll('p');
  let pArr = Array.from(p);
  pArr.forEach(function(item){
    console.log(item.textContent);  // 你好 我好 大家好
  })
  console.log(Array.from([1,3,5],function(item){return item*2})) // [2,6,10]
}

3.Array.fill

fill方法使用給定值,填充一個數(shù)組媚狰。

{
  console.log('fill-7',[1,3,'undefined'].fill(7));   //[7,7,7]
  console.log('fill,pos',[1,2,3,4,5,7,8].fill(7,1,4)); //[1, 7, 7, 7, 5, 7, 8]  // 后兩個參數(shù)表示索引的位置
}

4.entries()岛杀,keys() 和 values()

ES6 提供三個新的方法——entries(),keys()和values()——用于遍歷數(shù)組崭孤。

{
  for(let index of [1,2,3,4].keys()){
    console.log('index',index);
   // index 0
   // index 1
   // index 2
   // index 3
  }
  for(let value of [1,2,3,4].values()){
    console.log('value',value);
   // value 1
   // value 2
   // value 3
   // value 4
  }
  for(let [index,value] of [1,2,4,5,6].entries()){
    console.log(index,value);
   // 0 1
   // 1 2
   // 2 4
   // 3 5
   // 4 
  }
}

5.Array.copyWithin

截取一定長度的數(shù)字并且替換在相對應(yīng)的索引的位置

{
  console.log([1,4,9,6,7,2,3].copyWithin(1,3,5));  //  [1, 6, 7, 6, 7, 2, 3]  // 截取3-5的位置的數(shù)字类嗤,從索引1的位置開始替換
  console.log([1,4,9,6,7,2,3].copyWithin(1,3,6));  //  [1, 6, 7, 2, 7, 2, 3] 

}

6.findIndex和find

數(shù)組實例的find方法糊肠,用于找出第一個符合條件的數(shù)組成員。它的參數(shù)是一個回調(diào)函數(shù)遗锣,所有數(shù)組成員依次執(zhí)行該回調(diào)函數(shù)货裹,直到找出第一個返回值為true的成員,然后返回該成員精偿。如果沒有符合條件的成員弧圆,則返回undefined。數(shù)組實例的findIndex方法的用法與find方法非常類似笔咽,返回第一個符合條件的數(shù)組成員的位置搔预,如果所有成員都不符合條件,則返回-1拓轻。

{
  console.log([1,2,3,4,5,6].find(function(item){return item > 3}));   //4
  console.log([1,2,3,4,5,6].findIndex(function(item){return item > 3}));   // 3
}

7.includes

Array.prototype.includes方法返回一個布爾值斯撮,表示某個數(shù)組是否包含給定的值,與字符串的includes方法類似扶叉。ES2016 引入了該方法勿锅。

{
  console.log([1,2,NaN].includes(1));  // true
  console.log([1,2,NaN].includes(NaN));  // true
}

8.擴展運算符

擴展運算符(spread)是三個點(...)。將一個數(shù)組轉(zhuǎn)為用逗號分隔的參數(shù)序列枣氧。

console.log(...[1, 2, 3])
// 1 2 3

console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5

[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]

七 函數(shù)擴展

1.默認值

ES6 之前溢十,不能直接為函數(shù)的參數(shù)指定默認值;ES6允許為函數(shù)的參數(shù)設(shè)置默認值,即直接寫在參數(shù)定義的后面达吞。

{
    function fn(x,y='hello'){  // 默認值后面不能再出現(xiàn)形參
        console.log(x,y);
    }
    fn('word');  // word hello
    fn('word','nihao')  // word nihao
}

{
    let a = 'nihao';
    function test(a,b=a){  //1.
        //let a = 1; 參數(shù)變量是默認聲明的张弛,所以不能用let或const再次聲明
        console.log(a,b);
    }
    test('word'); // word word  
    test();  //undefined undefined
}
{
    let a = 'nihao';
    function test(x,b=a){  //2.
        console.log(x,b)
    }
    test('hello');// hello nihao
}

3.rest參數(shù)

ES6 引入rest參數(shù)(形式為...變量名),用于獲取函數(shù)的多余參數(shù)酪劫,這樣就不需要使用arguments對象了吞鸭。rest參數(shù)搭配的變量是一個數(shù)組,該變量將多余的參數(shù)放入數(shù)組中覆糟。

{
    function fn(...arg){
        for(let v of arg){
            console.log(v);
        }
    }
    fn(1,2,3,4);
    //1
    //2
    //3
    //4
}
{
    console.log(...[1,2,3,4]);  // 1刻剥,2,3滩字,4
    console.log('a',...[1,2,3,4]); // a,1,2,3,4
}

4.箭頭函數(shù)

ES6 允許使用“箭頭”(=>)定義函數(shù)造虏。

{
    let arr = v => v*2;
    console.log(arr(2));

    var sum = (num1, num2) => { return num1 + num2; } //如果箭頭函數(shù)的代碼塊部分多于一條語句,就要使用大括號將它們括起來麦箍,并且使用return語句返回漓藕。
}

使用注意點
箭頭函數(shù)有幾個使用注意點。

(1)函數(shù)體內(nèi)的this對象挟裂,就是定義時所在的對象享钞,而不是使用時所在的對象。

(2)不可以當作構(gòu)造函數(shù)诀蓉,也就是說嫩与,不可以使用new命令寝姿,否則會拋出一個錯誤交排。

(3)不可以使用arguments對象划滋,該對象在函數(shù)體內(nèi)不存在。如果要用埃篓,可以用 rest 參數(shù)代替处坪。

(4)不可以使用yield命令,因此箭頭函數(shù)不能用作 Generator 函數(shù)架专。

5.綁定 this

函數(shù)綁定運算符是并排的兩個冒號(::)同窘,雙冒號左邊是一個對象,右邊是一個函數(shù)部脚。該運算符會自動將左邊的對象想邦,作為上下文環(huán)境(即this對象),綁定到右邊的函數(shù)上面委刘。

foo::bar;
// 等同于
bar.bind(foo);

foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);

const hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn(obj, key) {
  return obj::hasOwnProperty(key);
}

尾調(diào)用(Tail Call)是函數(shù)式編程的一個重要概念丧没,本身非常簡單,一句話就能說清楚锡移,就是指某個函數(shù)的最后一步是調(diào)用另一個函數(shù)呕童。

{
    function fn1(x){
        console.log('fn1',x);
    }
    function fn2(x){
        return fn1(x);  // 對fn1的調(diào)用必須在最后一步操作
    }
    fn2(2);
}

八 對象擴展

1.屬性的簡介表示法

ES6 允許直接寫入變量和函數(shù),作為對象的屬性和方法淆珊。這樣的書寫更加簡潔夺饲。

{
    let a = 5,b=6;
    let es5 = {
        a:a,
        b:b
    }
    let es6 = {
        a,
        b
    }
    console.log(es5,es6)  // {a: 5, b: 6}  {a: 5, b: 6}


    let es5_fn = {   // 
        fn:function(){
            console.log('hello')
        }
    }
    let es6_fn = {
        fn(){
            console.log('hello')
        }
    }
    console.log(es5_fn.fn,es6_fn.fn);
}

2.動態(tài)key值

es6允許屬性的key值是動態(tài)的變量

{
    let a = 'b';
    let es5_obj = {
        a:'c',
        b:'c'
    }
    let es6_obj = {
        [a]:'c'   // a是動態(tài)的變量,可以自由賦值
    }
    console.log(es5_obj, es6_obj);
}

3.Object.is

這個方法相當于es5 中的 ===施符,來判斷屬性是否相等

{
    console.log('is',Object.is('a','a'));  // true
    console.log('is',Object.is([],[]));    // false   數(shù)組對象擁有不同的地址往声,
}

4.Object.assign

Object.assign方法用于對象的合并,將源對象的所有可枚舉屬性戳吝,復制到目標對象浩销。

{
    console.log('拷貝',Object.assign({a:1},{b:2}));  //淺拷貝

    let test = {a:2,b:3}
    for(let [key,value] of Object.entries(test)){   // 遍歷
        console.log([key,value]); 
        //[a:2]
        //[b:3]
    }
}

九 Symbol

1.Symbol簡單舉例

ES6引入了一種新的原始數(shù)據(jù)類型Symbol,表示獨一無二的值骨坑。

{
    let a1 = Symbol();
    let a2 = Symbol();
    console.log(a1===a2)   // false

    let a3 = Symbol.for('a3');
    let a4 = Symbol.for('a3');

    console.log(a3===a4);  //true
}

2.Symbol的一些API

Symbol.for可以用來命名具有相同的key值的對象撼嗓。
Object.getOwnPropertySymbols方法返回一個數(shù)組,成員是當前對象的所有用作屬性名的 Symbol 值欢唾。
Reflect.ownKeys方法可以返回所有類型的鍵名且警,包括常規(guī)鍵名和 Symbol 鍵名。

{
    let a1 = Symbol.for('abc');
    let obj = {
        [a1]:123,
        abc:234,
        c:345
    }
    console.log(obj); 
    // abc:234
    // c:345
    // Symbol(abc):123

    Object.getOwnPropertySymbols(obj).forEach(function(item){
        console.log('symbol',item,obj[item]); //symbol Symbol(abc) 123
    })
    Reflect.ownKeys(obj).forEach(function(item){
        console.log(item,obj[item]); 
        //abc 234
        //c 345
        //Symbol(abc) 123
    })

}

十 Map和Set數(shù)據(jù)結(jié)構(gòu)

1.set的基本用法

ES6 提供了新的數(shù)據(jù)結(jié)構(gòu) Set礁遣。它類似于數(shù)組斑芜,但是成員的值都是唯一的,沒有重復的值祟霍。Set 本身是一個構(gòu)造函數(shù)杏头,用來生成 Set 數(shù)據(jù)結(jié)構(gòu)盈包。 Set 結(jié)構(gòu)不會添加重復的值

{
    let list = new Set();
    list.add(2);
    list.add(3);
    console.log(list.size);  //2

    let arr = [1,2,3,4,5];
    let list2 = new Set(arr);
    console.log(list2.size); //5

    console.log(list2) //{1, 2, 3, 4, 5}

    let arr2 = [1,2,3,4,2,1];   //這里可以當作數(shù)組去重
    let list3 = new Set(arr2);
    console.log(list3) //{1, 2, 3, 4}

}

add(value):添加某個值叽粹,返回Set結(jié)構(gòu)本身烘绽。
delete(value):刪除某個值,返回一個布爾值原茅,表示刪除是否成功寓娩。
has(value):返回一個布爾值叛氨,表示該值是否為Set的成員。
clear():清除所有成員棘伴,沒有返回值寞埠。

{
    let arr = ['add','delete','clear','has'];
    let list = new Set(arr);
    console.log(list); // {"add", "delete", "clear", "has"}

    list.delete('add');
    console.log(list); // {"delete", "clear", "has"}

    console.log(list.has('clear')); // true

    list.clear();  
    console.log(list); //{}
    //set遍歷方法
    {
        let arr = ['add','delete','clear','has'];
        let list = new Set(arr);

        for(let key of list.keys()){
            console.log('keys',key)
            //keys add
            //keys delete
            //keys clear
            //keys has
        }
        for(let value of list.values()){
            console.log('values',value)
            //values add
            //values delete
            //values clear
            //values has
        }
        for(let [key,value] of list.entries()){
            console.log(key,value);
            //add add
            //delete delete
            //clear clear
            //has has
        }
        list.forEach(function(item){console.log(item)})
           // add
           // delete
           // clear
           // has
    }
}

2.WeakSet基本用法

WeakSet結(jié)構(gòu)與Set類似,也是不重復的值的集合焊夸。但是仁连,它與 Set有兩個區(qū)別。首先阱穗,WeakSet 的成員只能是對象饭冬,而不能是其他類型的值。
WeakSet中的對象都是弱引用颇象,即垃圾回收機制不考慮 WeakSet 對該對象的引用伍伤,也就是說,如果其他對象都不再引用該對象遣钳,那么垃圾回收機制會自動回收該對象所占用的內(nèi)存扰魂,不考慮該對象還存在于 WeakSet 之中。
WeakSet.prototype.add(value):向 WeakSet 實例添加一個新成員蕴茴。
WeakSet.prototype.delete(value):清除 WeakSet 實例的指定成員劝评。
WeakSet.prototype.has(value):返回一個布爾值,表示某個值是否在

{
    const ws = new WeakSet();
    ws.add(1)
    // TypeError: Invalid value used in weak set
    ws.add(Symbol())
    // TypeError: invalid value used in weak set

    let weakset = new WeakSet()  // 沒有clear倦淀,set方法蒋畜,不能遍歷
    let obj = {}   
    weakset.add(obj)
    // weekset.add(2)  WeakSet必須添加的是對象,弱引用   
    console.log(weakset);
}

3.Map的基本用法

ES6 提供了 Map 數(shù)據(jù)結(jié)構(gòu)撞叽。它類似于對象姻成,也是鍵值對的集合,但是“鍵”的范圍不限于字符串愿棋,各種類型的值(包括對象)都可以當作鍵科展。也就是說,Object結(jié)構(gòu)提供了“字符串—值”的對應(yīng)糠雨,Map結(jié)構(gòu)提供了“值—值”的

{
    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"
}
{
    let map = new Map();
    let arr = ['123'];
    map.set(arr,'456');
    console.log(map,map.get(arr)) // {["123"] => "456"} "456"
}

{
    let map = new Map([['a',123],['b',456]])
    console.log(map);                   //{"a" => 123, "b" => 456}
    console.log(map.size);              //2
    console.log('123'+map.delete('a')); //true
    console.log(map)                    // {"b" => 456}
    map.clear()
    console.log(map);                   //{}
}

4.WeakMap的一些API

WeakMap只接受對象作為鍵名(null除外)才睹,不接受其他類型的值作為鍵名。
WeakMap的鍵名所引用的對象都是弱引用,即垃圾回收機制不將該引用考慮在內(nèi)琅攘。因此垮庐,只要所引用的對象的其他引用都被清除,垃圾回收機制就會釋放該對象所占用的內(nèi)存坞琴。也就是說哨查,一旦不再需要,WeakMap里面的鍵名對象和所對應(yīng)的鍵值對會自動消失置济,不用手動刪除引用解恰。
WeakMap 與 Map 在 API 上的區(qū)別主要是兩個,一是沒有遍歷操作(即沒有key()浙于、values()和entries()方法),也沒有size屬性挟纱。因為沒有辦法列出所有鍵名羞酗,某個鍵名是否存在完全不可預(yù)測,跟垃圾回收機制是否運行相關(guān)紊服。這一刻可以取到鍵名檀轨,下一刻垃圾回收機制突然運行了,這個鍵名就沒了欺嗤,為了防止出現(xiàn)不確定性参萄,就統(tǒng)一規(guī)定不能取到鍵名。二是無法清空煎饼,即不支持clear方法讹挎。因此,WeakMap只有四個方法可用:get()吆玖、set()筒溃、has()、delete()沾乘。

{
    let weakmap = new WeakMap() //沒有clear怜奖,set方法,不能遍歷
    let o = {}
    weakmap.set(o,123);
    console.log(weakmap.get(o));
}

十一 proxy和reflect

1.Proxy

Proxy用于修改某些操作的默認行為翅阵,等同于在語言層面做出修改歪玲,所以屬于一種“元編程”(meta programming),即對編程語言進行編程掷匠。Proxy 可以理解成滥崩,在目標對象之前架設(shè)一層“攔截”,外界對該對象的訪問槐雾,都必須先通過這層攔截夭委,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。Proxy這個詞的原意是代理株灸,用在這里表示由它來“代理”某些操作崇摄,可以譯為“代理器”。

{
  let obj = {
    name:'gao',
    time:'2017-08-13',
    emp:'123',
  }
  let temp = new Proxy(obj,{
    get(target,key){
          return target[key].replace('2017','2018');
    },
    set(target,key,value){
      if(key === 'name'){
        return target[key] = value;
      }else{
        return target[key];
      }
    },
    has(target,key){
      if(key === 'name'){
        return target[key];
      }else{
        return false;
      }
    },
    deleteProperty(target,key){
      if(key.indexOf('i') > -1){
        delete target[key];
        return true;
      }else{
        return target[key];
      }
    },
    ownKeys(target){
      return Object.keys(target).filter(item=>item!='name');
    }
  })

  console.log('get',temp.time);  //get 2018-08-13

  temp.time = '2018';
  console.log('set',temp.name,temp); //set gao   {name: "gao", time: "2017-08-13", temp: "123"}

  temp.name = 'he';
  console.log('set',temp.name,temp); // set he  {name: "he", time: "2017-08-13", temp: "123"}

  console.log('has','name' in temp,'time' in temp);  //has true false

  delete temp.time;
  console.log('delete',temp);   //delete  {name: "he", temp: "123"}

  console.log('ownkeys',Object.keys(temp));  //["emp"]
}

2.Reflect

Reflect對象與Proxy對象一樣慌烧,也是 ES6 為了操作對象而提供的新 API逐抑。Reflect對象的設(shè)計目的有這樣幾個。
(1) 將Object對象的一些明顯屬于語言內(nèi)部的方法(比如Object.defineProperty)屹蚊,放到Reflect對象上〔薨保現(xiàn)階段,某些方法同時在Object和Reflect對象上部署汹粤,未來的新方法將只部署在Reflect對象上命斧。也就是說,從Reflect對象上可以拿到語言內(nèi)部的方法嘱兼。
(2) 修改某些Object方法的返回結(jié)果国葬,讓其變得更合理。比如芹壕,Object.defineProperty(obj, name, desc)在無法定義屬性時汇四,會拋出一個錯誤,而Reflect.defineProperty(obj, name, desc)則會返回false踢涌。
(3) 讓Object操作都變成函數(shù)行為通孽。某些Object操作是命令式,比如name in obj和delete obj[name]睁壁,而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)讓它們變成了函數(shù)行為背苦。
(4)Reflect對象的方法與Proxy對象的方法一一對應(yīng),只要是Proxy對象的方法堡僻,就能在Reflect對象上找到對應(yīng)的方法糠惫。這就讓Proxy對象可以方便地調(diào)用對應(yīng)的Reflect方法,完成默認行為钉疫,作為修改行為的基礎(chǔ)硼讽。也就是說,不管Proxy怎么修改默認行為牲阁,你總可以在Reflect上獲取默認行為固阁。

{
  let obj = {
    name:'gao',
    time:'2017-08-13',
    emp:'123',
  }
  console.log('reflect get',Reflect.get(obj, 'name'));  // reflect get gao
  Reflect.set(obj,'name','hexaiofei');
  console.log(obj);  // {name: "hexaiofei", time: "2017-08-13", emp: "123"}
  console.log('reflect has', Reflect.has(obj,'name'));  //reflect has true
}

3.簡單應(yīng)用

{
  function validator(target,validator) {
    return new Proxy(target,{
      _validator:validator,
      set(target,key,value,proxy){
        if(target.hasOwnProperty(key)){
          let va = this._validator[key];
          if(!!va(value)){
            return Reflect.set(target,key,value,proxy);
          }else{
            throw Error(`不能設(shè)置${key}到${value}`);
          }
        }else{
          throw Error(`${key}不存在`);
        }
      }
    })
  }

  const personValidators={
    name(value){
      return typeof value === 'string'
    },
    age(value){
      return typeof value === 'number' && value > 18;
    }
  }

  class Person{
    constructor(name,age) {
      this.name = name;
      this.age = age;
      return validator(this,personValidators)
    }
  }

  const person = new Person('lilei',30);
  console.log(person);

  person.name = 48;

}

十二 Class的基本語法

1.簡介

ES6 提供了更接近傳統(tǒng)語言的寫法,引入了Class(類)這個概念城菊,作為對象的模板备燃。通過class關(guān)鍵字,可以定義類凌唬〔⑵耄基本上,ES6的class可以看作只是一個語法糖,它的絕大部分功能况褪,ES5 都可以做到撕贞,新的class寫法只是讓對象原型的寫法更加清晰、更像面向?qū)ο缶幊痰恼Z法而已测垛。

{
  class Parent {
    constructor(name='gao') {
      this.name = name;
    } 
  }

  let v_parent = new Parent();
  console.log(v_parent);  //{name: "gao"}
}

2.繼承

Class可以通過extends關(guān)鍵字實現(xiàn)繼承捏膨,這比ES5的通過修改原型鏈實現(xiàn)繼承,要清晰和方便很多食侮。

{
  class Parent {
    constructor(name='gao') {
      this.name = name;
    } 
  }

  class child extends Parent {

  }
  let v_child = new child();
  console.log(v_child);  //{name: "gao"}
}

3.constructor

constructor方法是類的默認方法号涯,通過new命令生成對象實例時,自動調(diào)用該方法锯七。一個類必須有constructor方法链快,如果沒有顯式定義,一個空的constructor方法會被默認添加起胰。

4.super關(guān)鍵字

super這個關(guān)鍵字久又,既可以當作函數(shù)使用,也可以當作對象使用效五。在這兩種情況下,它的用法完全不同炉峰。第一種情況畏妖,super作為函數(shù)調(diào)用時,代表父類的構(gòu)造函數(shù)疼阔。ES6 要求戒劫,子類的構(gòu)造函數(shù)必須執(zhí)行一次super函數(shù)。第二種情況婆廊,super作為對象時迅细,在普通方法中,指向父類的原型對象淘邻;在靜態(tài)方法中茵典,指向父類。super()在子類constructor構(gòu)造方法中是為了獲取this上下文環(huán)境,所以如果在constructor中使用到this,必須在使用this之前調(diào)用super(),反之不在constructor中使用this則不必調(diào)用super()

{
  class Parent {
    constructor(name='gao') {
      this.name = name;
    } 
  }
  class child extends Parent {
    constructor(name='child'){
      super(name);
      this.type = 'child'
    }
    
  }
  let v_child = new child();
  console.log(v_child);  //{name: "child", type: "child"}
}

5.getter和setter

與 ES5 一樣宾舅,在“類”的內(nèi)部可以使用get和set關(guān)鍵字统阿,對某個屬性設(shè)置存值函數(shù)和取值函數(shù),攔截該屬性的存取行為筹我。

{
  class Parent {
    constructor(name='gao') {
      this.name = name;
    } 
    get longName(){
      return 'mk' + this.name;
    }
    set longName(value){
      // console.log(value);
      this.name = value;
    }
  }

  
  let v_parent = new Parent();
  console.log('get',v_parent.longName);  //get mkgao

  v_parent.longName = 'hello';
  console.log('get',v_parent.longName);  //get mkhello
}

6.靜態(tài)方法

類相當于實例的原型扶平,所有在類中定義的方法,都會被實例繼承蔬蕊。如果在一個方法前结澄,加上static關(guān)鍵字,就表示該方法不會被實例繼承,而是直接通過類來調(diào)用麻献,這就稱為“靜態(tài)方法”们妥。

{
  class Parent {
    constructor(name='gao') {
      this.name = name;
    } 
    static tell(){
      console.log('tell');
    }
  }

  let v_parent = new Parent();
  console.log(v_parent);  //{name: "gao"}
  Parent.tell(); // tell
}

7.靜態(tài)屬性

靜態(tài)屬性指的是Class本身的屬性,即Class.propName赎瑰,而不是定義在實例對象(this)上的屬性王悍。

{
  class Parent {
    constructor(name='gao') {
      this.name = name;
    } 
    
  }
  Parent.tell = 'nihao';

  let v_parent = new Parent();
  console.log(v_parent);  //{name: "gao"}
  console.log(Parent.tell);   // nihao
}

十三 Promise

Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大餐曼。它由社區(qū)最早提出和實現(xiàn)压储,ES6 將其寫進了語言標準,統(tǒng)一了用法源譬,原生提供了Promise對象集惋。所謂Promise,簡單說就是一個容器踩娘,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果刮刑。從語法上說,Promise 是一個對象养渴,從它可以獲取異步操作的消息雷绢。Promise 提供統(tǒng)一的 API,各種異步操作都可以用同樣的方法進行處理理卑。
Promise對象有以下兩個特點翘紊。
(1)對象的狀態(tài)不受外界影響。Promise對象代表一個異步操作藐唠,有三種狀態(tài):Pending(進行中)帆疟、Fulfilled(已成功)和Rejected(已失敗)宇立。只有異步操作的結(jié)果踪宠,可以決定當前是哪一種狀態(tài),任何其他操作都無法改變這個狀態(tài)妈嘹。這也是Promise這個名字的由來柳琢,它的英語意思就是“承諾”,表示其他手段無法改變蟋滴。
(2)一旦狀態(tài)改變染厅,就不會再變,任何時候都可以得到這個結(jié)果津函。Promise對象的狀態(tài)改變肖粮,只有兩種可能:從Pending變?yōu)镕ulfiled和從Pending變?yōu)镽ejected。只要這兩種情況發(fā)生尔苦,狀態(tài)就凝固了涩馆,不會再變了行施,會一直保持這個結(jié)果,這時就稱為 Resolved(已定型)魂那。如果改變已經(jīng)發(fā)生了蛾号,你再對Promise對象添加回調(diào)函數(shù),也會立即得到這個結(jié)果涯雅。這與事件(Event)完全不同鲜结,事件的特點是,如果你錯過了它活逆,再去監(jiān)聽精刷,是得不到結(jié)果的。

注意蔗候,為了行文方便怒允,本章后面的Resolved統(tǒng)一只指Fulfilled狀態(tài),不包含Rejected狀態(tài)锈遥。

有了Promise對象纫事,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調(diào)函數(shù)所灸。此外丽惶,Promise對象提供統(tǒng)一的接口,使得控制異步操作更加容易爬立。

Promise也有一些缺點蚊夫。首先,無法取消Promise懦尝,一旦新建它就會立即執(zhí)行,無法中途取消壤圃。其次陵霉,如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯誤伍绳,不會反應(yīng)到外部踊挠。第三,當處于Pending狀態(tài)時冲杀,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)效床。

如果某些事件不斷地反復發(fā)生,一般來說权谁,使用 Stream 模式是比部署Promise更好的選擇剩檀。

1.基本用法

Promise構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)的兩個參數(shù)分別是resolve和reject旺芽。它們是兩個函數(shù)沪猴,由 JavaScript 引擎提供辐啄,不用自己部署。

resolve函數(shù)的作用是运嗜,將Promise對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α保磸?Pending 變?yōu)?Resolved)壶辜,在異步操作成功時調(diào)用,并將異步操作的結(jié)果担租,作為參數(shù)傳遞出去砸民;reject函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤笆 保磸?Pending 變?yōu)?Rejected)奋救,在異步操作失敗時調(diào)用岭参,并將異步操作報出的錯誤,作為參數(shù)傳遞出去菠镇。

Promise實例生成以后冗荸,可以用then方法分別指定Resolved狀態(tài)和Rejected狀態(tài)的回調(diào)函數(shù)。

// ES5的回調(diào)函數(shù)
{
  let ajax = function(callback){
    console.log('nihao');
    setTimeout(function(){
      callback && callback.call()
    },1000)
  }
  ajax(function(){
    console.log('timeout1');
  })
}
// es6 Promise的用法
{
  let ajax = function(){
    console.log('wohao');
    return new Promise((resolve, reject) => {
      setTimeout(function(){
        resolve();
      },1000);
    });
  }
  ajax().then(function(){
    console.log('promise','timeout1');
  })
}

promise.then(function(value) {   // promise的用法
  // success
}, function(error) {
  // failure
});

2.Promise.prototype.then()

Promise實例具有then方法利耍,也就是說蚌本,then方法是定義在原型對象Promise.prototype上的。它的作用是為 Promise 實例添加狀態(tài)改變時的回調(diào)函數(shù)隘梨。前面說過程癌,then方法的第一個參數(shù)是Resolved狀態(tài)的回調(diào)函數(shù),第二個參數(shù)(可選)是Rejected狀態(tài)的回調(diào)函數(shù)轴猎。
then方法返回的是一個新的Promise實例(注意嵌莉,不是原來那個Promise實例)。因此可以采用鏈式寫法捻脖,即then方法后面再調(diào)用另一個then方法锐峭。

{
  let ajax = function(){
    console.log('dajiahao');
    return new Promise((resolve, reject) => {
      setTimeout(function(){
        resolve();
      },1000);
    });
  };
  ajax().then(function(){
    return new Promise((resolve, reject) => {
      setTimeout(function(){
        resolve();
      },2000)
    });
  })
  .then(function(){
    console.log('timeout3');
  })
}

3.Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的別名,用于指定發(fā)生錯誤時的回調(diào)函數(shù)可婶。

{
  let ajax = function(num){
    console.log('dajiahao');
    return new Promise((resolve, reject) => {
      if(num>6){
        console.log('6');
      }else{
        throw new Error('出錯了');
      }
    });
  };

  ajax(3).then(function(){
    console.log('3');
  })
  .catch(error=>{
    console.log(error)   //出錯了
  })


}

4.Promise.all

Promise.all方法用于將多個 Promise 實例沿癞,包裝成一個新的 Promise 實例。

var p = Promise.all([p1, p2, p3]);

上面代碼中矛渴,Promise.all方法接受一個數(shù)組作為參數(shù)椎扬,p1、p2具温、p3都是 Promise 實例蚕涤,如果不是,就會先調(diào)用下面講到的Promise.resolve方法铣猩,將參數(shù)轉(zhuǎn)為 Promise 實例揖铜,再進一步處理。(Promise.all方法的參數(shù)可以不是數(shù)組剂习,但必須具有 Iterator 接口蛮位,且返回的每個成員都是 Promise 實例较沪。)

p的狀態(tài)由p1、p2失仁、p3決定尸曼,分成兩種情況。

(1)只有p1萄焦、p2控轿、p3的狀態(tài)都變成fulfilled,p的狀態(tài)才會變成fulfilled拂封,此時p1茬射、p2、p3的返回值組成一個數(shù)組冒签,傳遞給p的回調(diào)函數(shù)在抛。

(2)只要p1、p2萧恕、p3之中有一個被rejected刚梭,p的狀態(tài)就變成rejected,此時第一個被reject的實例的返回值票唆,會傳遞給p的回調(diào)函數(shù)朴读。

{
  function loadImg(src){
    return new Promise((resolve, reject) => {
      let img = document.createElement('img');
      img.src=src;
      img.onload = function(){
        resolve(img);
      }
      img.onerror = function(error){
        reject(error);  
      }
    });
  }
  function showImgs(imgs){
    imgs.forEach(function(img){
      document.body.appendChild(img);
    })
  }
  Promise.all([
    loadImg(''),
    loadImg(''),
    loadImg(''),
  ]).then(showImgs)
}

4.Promise.race

Promise.race方法同樣是將多個Promise實例,包裝成一個新的Promise實例走趋。

var p = Promise.race([p1, p2, p3]);

上面代碼中衅金,只要p1、p2簿煌、p3之中有一個實例率先改變狀態(tài)氮唯,p的狀態(tài)就跟著改變。那個率先改變的 Promise 實例的返回值姨伟,就傳遞給p的回調(diào)函數(shù)您觉。
Promise.race方法的參數(shù)與Promise.all方法一樣,如果不是 Promise 實例授滓,就會先調(diào)用下面講到的Promise.resolve方法,將參數(shù)轉(zhuǎn)為 Promise 實例肆糕,再進一步處理般堆。
下面是一個例子,如果指定時間內(nèi)沒有獲得結(jié)果诚啃,就將Promise的狀態(tài)變?yōu)閞eject淮摔,否則變?yōu)閞esolve。

{
  function loadImg(src){
    return new Promise((resolve, reject) => {
      let img = document.createElement('img');
      img.src=src;
      img.onload = function(){
        resolve(img);
      }
      img.onerror = function(error){
        reject(error);  
      }
    });
  }
  function showImg(img){
    let img = document.createElement('p');
    p.appendChild(img);
    document.body.appendChild(p);
  }

  Promise.race([
    loadImg(''),
    loadImg(''),
    loadImg(''),
  ]).then(showImgs)
}

十四 Iterator 和 for...of 循環(huán)

Iterator 接口的目的始赎,就是為所有數(shù)據(jù)結(jié)構(gòu)和橙,提供了一種統(tǒng)一的訪問機制仔燕,即for...of循環(huán)。當使用for...of循環(huán)遍歷某種數(shù)據(jù)結(jié)構(gòu)時魔招,該循環(huán)會自動去尋找 Iterator 接口晰搀。一種數(shù)據(jù)結(jié)構(gòu)只要部署了 Iterator 接口,我們就稱這種數(shù)據(jù)結(jié)構(gòu)是”可遍歷的“(iterable)办斑。
ES6 規(guī)定外恕,默認的 Iterator 接口部署在數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator屬性,或者說乡翅,一個數(shù)據(jù)結(jié)構(gòu)只要具有Symbol.iterator屬性鳞疲,就可以認為是“可遍歷的”(iterable)。Symbol.iterator屬性本身是一個函數(shù)蠕蚜,就是當前數(shù)據(jù)結(jié)構(gòu)默認的遍歷器生成函數(shù)尚洽。執(zhí)行這個函數(shù),就會返回一個遍歷器靶累。至于屬性名Symbol.iterator腺毫,它是一個表達式,返回Symbol對象的iterator屬性尺铣,這是一個預(yù)定義好的拴曲、類型為 Symbol的特殊值,所以要放在方括號內(nèi)凛忿。

1.數(shù)組的Symbol.iterator屬性

變量arr是一個數(shù)組澈灼,原生就具有遍歷器接口,部署在arr的Symbol.iterator屬性上面店溢。所以叁熔,調(diào)用這個屬性,就得到遍歷器對象床牧。

{
  let arr = ['hellow','world'];
  let map = arr[Symbol.iterator]();
  console.log(map.next());  //{value: "hellow", done: false}
  console.log(map.next());  //{value: "world", done: false}
  console.log(map.next());  //{value: "undefined", done: false}
}

2.自定義的Iterator接口

{
  let obj = {
    start:[1,3,2],
    end:[7,8,9],
    [Symbol.iterator](){
      let self = this;
      let index = 0;
      let arr = self.start.concat(self.end);
      let len = arr.length;
      return {
        next(){
          if(index<len){
            return {
              value:arr[index++],
              done:false
            }
          }else{
            return {
              value:arr[index++],
              done:true
            }
          }
        }
      }
    }
  }
  for(let key of obj){
    console.log(key); //1 3 2 7 8 9
  }
}

十五 Genertor

1.基本概念

Generator 函數(shù)有多種理解角度荣回。從語法上,首先可以把它理解成戈咳,Generator函數(shù)是一個狀態(tài)機心软,封裝了多個內(nèi)部狀態(tài)。執(zhí)行 Generator 函數(shù)會返回一個遍歷器對象著蛙,也就是說删铃,Generator函數(shù)除了狀態(tài)機,還是一個遍歷器對象生成函數(shù)踏堡。返回的遍歷器對象猎唁,可以依次遍歷Generator函數(shù)內(nèi)部的每一個狀態(tài)。形式上顷蟆,Generator 函數(shù)是一個普通函數(shù)诫隅,但是有兩個特征腐魂。一是,function關(guān)鍵字與函數(shù)名之間有一個星號逐纬;二是蛔屹,函數(shù)體內(nèi)部使用yield表達式,定義不同的內(nèi)部狀態(tài)(yield在英語里的意思就是“產(chǎn)出”)风题。

{
  let tell = function* (){
    yield 'a';
    yield 'b';
    return 'c';
  }
  let k = tell();
  console.log(k.next()); //{value: "a", done: false}
  console.log(k.next()); //{value: "b", done: false}
  console.log(k.next()); //{value: "c", done: true}
  console.log(k.next()); //{value: undefined, done: true}
}

2.與 Iterator 接口的關(guān)系

由于 Generator 函數(shù)就是遍歷器生成函數(shù)判导,因此可以把Generator賦值給對象的Symbol.iterator屬性,從而使得該對象具有 Iterator 接口沛硅。


{
  let obj = {};
  obj[Symbol.iterator] = function* (){
    yield '1';
    yield '2';
    yield '3';
  }
  for(let value of obj){
    console.log(value); // 1 2 3
  }
}

3.next方法

{
  let state = function* (){
      yield 'a';
      yield 'b';
      yield 'c';
  }
  let status = state();
  console.log(status.next());  //a
  console.log(status.next());  //b
  console.log(status.next());  //c
  console.log(status.next());  //a
  console.log(status.next());  //b
  console.log(status.next());  //c
  console.log(status.next());  //a
}

4.Genertor的簡單應(yīng)用

//簡單的抽獎
{
  let draw = function(count){
    console.info(`剩余${count}次`);
  }
  let chou = function *(count){
    while (count>0) {
      count--;
      yield draw(count);
    }
  }
  let start = chou(5);
  let btn = document.createElement('button');
  btn.id = 'start';
  btn.textContent = '抽獎';
  document.body.appendChild(btn);
  document.getElementById('start').addEventListener('click',function(){
    start.next();
  },false);
}
// 長輪詢
{
  let ajax = function* (){
    yield new Promise((resolve, reject) => {
      setTimeout(function(){
        resolve({code:1})
      },200)
    });
  }
  let pull = function(){
    let generator = ajax();
    let step = generator.next();
    step.value.then(function(d){
      if(d.code != 0){
        setTimeout(function(){
          console.log('wait');   //隔一秒輸出 wait
          pull();
        },1000)
      }else{
        console.log(d);
      }
    })
  }
  pull();
}

十六修飾器

1.方法的修飾

修飾器函數(shù)一共可以接受三個參數(shù)眼刃,第一個參數(shù)是所要修飾的目標對象,即類的實例(這不同于類的修飾摇肌,那種情況時target參數(shù)指的是類本身)擂红;第二個參數(shù)是所要修飾的屬性名,第三個參數(shù)是該屬性的描述對象围小。

{
  let readonly = function(target,name,descriptor){
    descriptor.writable = false;
    return descriptor;
  };
  class test{
    @readonly
    time(){
      return '2017-08-27'
    }
  }
  let tests = new test();


  console.log(tests.time());  // 2017-08-27


  // let testss = new test();
  // // tests.time = function(){
  // //   console.log('2017-08-28');
  // // }
  // console.log(tests.time());  //Cannot assign to read only property 'time' of object
}

2.類的修飾

修飾器是一個對類進行處理的函數(shù)昵骤。修飾器函數(shù)的第一個參數(shù),就是所要修飾的目標類肯适。

{
  let typename = function(target,name,descriptor){
    target.myname = 'hello';
  };
  @typename
  class test{

  }

  console.log(test.myname) // hello
}

十七模塊化

ES6 模塊不是對象变秦,而是通過export命令顯式指定輸出的代碼,再通過import命令輸入框舔。

{
  export let A = 123;
  export function text(){
    console.log('123');
  }
  export class hello{
    text(){
      console.log('345');
    }
  }
}

{
  let A = 123;
  function text(){
    console.log('123');
  }
  class hello{
    text(){
      console.log('345');
    }
  }
  export default {
    A,
    text,
    hello
  }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蹦玫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子刘绣,更是在濱河造成了極大的恐慌樱溉,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纬凤,死亡現(xiàn)場離奇詭異福贞,居然都是意外死亡,警方通過查閱死者的電腦和手機停士,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門挖帘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恋技,你說我怎么就攤上這事肠套。” “怎么了猖任?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瓷耙。 經(jīng)常有香客問我朱躺,道長刁赖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任长搀,我火速辦了婚禮宇弛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘源请。我一直安慰自己枪芒,他們只是感情好,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布谁尸。 她就那樣靜靜地躺著舅踪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪良蛮。 梳的紋絲不亂的頭發(fā)上抽碌,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天,我揣著相機與錄音决瞳,去河邊找鬼货徙。 笑死,一個胖子當著我的面吹牛皮胡,可吹牛的內(nèi)容都是我干的痴颊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼屡贺,長吁一口氣:“原來是場噩夢啊……” “哼蠢棱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起烹笔,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤裳扯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谤职,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饰豺,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年允蜈,在試婚紗的時候發(fā)現(xiàn)自己被綠了冤吨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡饶套,死狀恐怖漩蟆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情妓蛮,我是刑警寧澤怠李,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響捺癞,放射性物質(zhì)發(fā)生泄漏夷蚊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一髓介、第九天 我趴在偏房一處隱蔽的房頂上張望惕鼓。 院中可真熱鬧,春花似錦唐础、人聲如沸箱歧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽呀邢。三九已至,卻和暖如春汞幢,著一層夾襖步出監(jiān)牢的瞬間驼鹅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工森篷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留输钩,地道東北人。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓仲智,卻偏偏與公主長得像买乃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子钓辆,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容

  • [TOC] 參考阮一峰的ECMAScript 6 入門參考深入淺出ES6 let和const let和const都...
    郭子web閱讀 1,781評論 0 1
  • 異步編程對JavaScript語言太重要剪验。Javascript語言的執(zhí)行環(huán)境是“單線程”的,如果沒有異步編程前联,根本...
    呼呼哥閱讀 7,311評論 5 22
  • 本文為阮一峰大神的《ECMAScript 6 入門》的個人版提純功戚! babel babel負責將JS高級語法轉(zhuǎn)義,...
    Devildi已被占用閱讀 1,983評論 0 4
  • Promiese 簡單說就是一個容器似嗤,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果啸臀,語法上說,Pr...
    雨飛飛雨閱讀 3,358評論 0 19
  • 線程同步的工具 原子操作原子操作是同步簡單的形式烁落。它處理簡單的數(shù)據(jù)類型乘粒。原子操作的優(yōu)勢它們不妨礙競爭的線程。 內(nèi)存...
    Crazy2015閱讀 240評論 0 0