ES6

1. let

1. let只在當前代碼塊內有效。
for(let i=0;i<arr.length;i++){
.....
}
console.log(i) // i is not defined

2. let不存在變量提升
3. 暫時性死區
var temp=123;
if(true){
let temp=4556;
//內部temp相當於一個局部變量,在聲明之前,該變量不可使用。在語法上稱爲“暫時性死區”
}
console.log(temp) // 123

4. 不允許重複聲明
let 不允許在相同作用域({})內重複聲明一個變量。
ES6允許塊級作用域任意嵌套,且外層作用域無法讀取內層作用域的變量。
5. ES6規定,塊級作用域中,函數聲明語句類似let,塊級作用域外不可引用

2. const

const聲明是一個只讀的常量,不能改變
只在聲明所在的塊級作用域內有效

notice:

var 命令和function命令聲明的全局變量依舊是全局對象的屬性,let,const命令聲明的全局變量不再屬於全局對象的屬性。

3. 變量解構賦值

  1. 數組解構賦值: var [a,b,c]=[1,2,3]
  2. 對象解構賦值:
    var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
    baz // "aaa"
  3. 字符串解構賦值
  4. 函數參數解構賦值

用途
- 交換變量值 eg. [x,y]=[y,x]
- 從函數返回多個值。
- function example(){
return [1,2,3];
}
var [a,b,c]=example();

- 函數參數的定義
- // 參數是一組有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

- 提取JSON數據
var jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]

  • 函數參數的默認值
    jQuery.ajax = function (url, {
    async = true,
    beforeSend = function () {},
    cache = true,
    complete = function () {},
    crossDomain = false,
    global = true,
    // ... more config
    }) {
    // ... do stuff
    };
  • 遍歷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

  • 輸入模塊的指定方法:
    const { SourceMapConsumer, SourceNode } = require("source-map");

4. 字符串的擴展

  1. codePointAt([index]):返回對應位置字符的碼點
  2. String.fromCodePoint([unicode]):用於從碼點返回對應字符。
  3. at():返回字符串給定位置的字符。
  4. for….of: 新增字符串遍歷接口
  5. includes(), startsWith(),endsWith(): 返回布爾值。
  6. repeat(n): 返回重複n次的字符串
  7. padStart(), padEnd(): ES7推出,頭部、尾部補全。
    'x'.padStart(5, 'ab') // 'ababx'
    'x'.padStart(4, 'ab') // 'abax'
    'x'.padEnd(5, 'ab') // 'xabab'
    'x'.padEnd(4, 'ab') // 'xaba'

  8. 模板字符串:(“),模板字符串中嵌入變量,需要將變量名寫在${}之中。

  9. String.raw()

5. 正則的擴展
6. 數值的擴展

  1. Number.isFinite(), Number.isNaN(): 只對數值數值有效,否則一律返回false
  2. Number.parseInt(), Number.parseFloat();
  3. Number.isInteger(): 3和3.0爲同一個值。
  4. Number.EPSILON,新增一個極小常量。
  5. Math對象的擴展


  1. Math.trunc(): 去除一個數的小數部分,返回整數部分。
  2. Math.sign(): 用來判斷一個數是正數,負數,零。

參數爲正數,返回+1;
參數爲負數,返回-1;
參數爲0,返回0;
參數爲-0,返回-0;
其他值,返回NaN。

7. 數組的擴展

1 . Array.from(arrlike,[func],[context]): 將類數組和可遍歷的對象轉換爲數組。功能類似於ES5:[].slice.call(arraylike)。第二個參數,類似於map方法,將處理後的值放入返回的數組。第三個參數,傳入this的環境。
2 . 擴展運算符:(…)也可以將某些數據轉換爲數組。eg. function foo() {
var args = [...arguments];
}

3 . Array.of(): 將一組值轉換爲數組。Array.of(3, 11, 8) // [3,11,8]
4 . copyWithin(target, start = 0, end = this.length):

target(必需):從該位置開始替換數據。
start(可選):從該位置開始讀取數據,默認爲0。如果爲負值,表示倒數。
end(可選):到該位置前停止讀取數據,默認等於數組長度。如果爲負值,表示倒數。

5 . find(): 用於找到第一個符合條件的數組成員。
6 . findIndex(): 返回第一個符合條件的數組成員的位置
7 . fill(): 使用給定值,填充一個數組。
8 . 數組實例的:entries(),keys(),values()

for (let index of ['a', 'b'].keys()) {
  console.log(index);
}

9 . includes(): Array.prototype.includes返回一個布爾值。

8. 函數的擴展
1 . ES6允許爲函數的參數設置默認值,即直接寫在參數定義的後面。eg. function log(x, y = 'World') {
console.log(x, y);
}

2.(…): 可以將一個數組轉爲逗號分隔的參數序列。
3 . name屬性:返回該函數的函數名。

4 . 箭頭函數

如果箭頭函數的代碼塊部分多於一條語句,需要用大括號括起來,並使用return返回。
1. 函數體內的this對象,是定義時所在的對象,不是使用時所在的對象。
2. 不可以當作構造函數,即不能使用new命令,否則報錯。
3. 不可以使用arguments對象,該對象在函數體內不存在。
4. 不可以使用yield命令。

5 . 函數綁定
函數綁定運算符:(::),左邊是對象,右邊爲函數,運算符會自動將左邊對象作爲上下文環境。

6 . 尾調用優化,尾遞歸

9. 對象的擴展
1 . 屬性簡潔表示:

  1. ES6允許在對象中,只寫屬性名,不寫屬性值,這時屬性值等於屬性名所代表的變量。eg.
    function f(x, y) {
    return {x: x, y: y};
    }
    f(1, 2) // Object {x: 1, y: 2}
  2. 方法也可以簡寫: eg.
    var o={method(){return 'hello!'}}
  3. ES6允許字面量定義對象,使用變量作爲屬性名。eg:
    let obj = {[propKey]: true, ['a' + 'bc']: 123
    };
  4. 屬性名表達式與簡潔表示法不能同時使用。

2 . Object.is(): 比較兩個值是否嚴格相等,基本與“===”相同,但+0不等於-0,二是NaN等於自身。

Object.is('foo', 'foo')
// true
Object.is({}, {})
// false

3 . Object.assign(): 用於對象的合併,只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉屬性。

var target = { a: 1 };

var source1 = { b: 2 };
var source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

notes:
- Object.assign是淺拷貝,即如果源對象某個屬性的值是對象,那麼目標對象得到的是對這個對象的引用。如果源對象發生變化,目標對象的屬性也會改變。
- Object.assign還能用來處理數組,但會把數組視爲對象。eg:
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]

4 . 屬性遍歷:

  1. for…in
  2. Object.keys(obj): 返回自身所有可枚舉屬性的數組
  3. Object.getOwnPropertyNames(obj): 返回自身的所有屬性的數組。
  4. Object.getOwnPropertySymbols(obj):返回一個數組,包含自身所有symbol屬性。
  5. Refletc.ownKeys(obj)
  1. __proto__屬性: 讀取或設置當前prototype對象。可以用:Object.setPrototypeOf()(寫操作)、Object.getPrototypeOf()(讀操作)、Object.create()(生成操作)代替
  2. Object.setPrototypeOf():設置對象的prototype對象。
  3. Object.getPrototypeOf():讀取
  4. Object.values(), Object.entries(),Object.keys

5 . 對象的擴展運算符

  1. Rest解構賦值(…): 用於從一個對象取值,將所有可遍歷但未讀取的屬性,分配到對象上。
    eg:
    let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
    x // 1
    y // 2
    z // { a: 3, b: 4 }
  2. 擴展運算符(…): 用於取出參數對象的所有可遍歷屬性,拷貝到當前對象中。

10 . Symbol
原始數據類型,表示獨一無二的值,保證對象的屬性獨一無二。

Symbol作爲屬性名,該屬性不會出現在for…in、for…of循環中,也不會被Object.keys()、Object.getOwnPropertyNames()返回。但是,它也不是私有屬性,有一個Object.getOwnPropertySymbols方法,可以獲取指定對象的所有Symbol屬性名。
Object.getOwnPropertySymbols方法返回一個數組,成員是當前對象的所有用作屬性名的Symbol值。

11 . Set和Map數據結構
set
類似於數組,成員值都是唯一的,無重複。

var s=new Set();
[2, 3, 5, 4, 5, 2, 2].map(x => s.add(x));
 log([...s])// [1, 2, 3]
 log(Array.from(s))//[1, 2, 3]
 log(s)//Set(3) {1, 2, 3}

1 . set 函數可以接受一個數組或類數組作爲對象,轉換爲set數據。

var set = new Set([1, 2, 3, 4, 4]);
[...set]
// [1, 2, 3, 4]
> 向set加入值,不會發生類型轉換。5和"5"是不同值,但NaN等於NaN。

2 . set實例屬性和方法:
- Set.prototype.constructor:構造函數,默認就是Set函數。
- Set.prototype.size:返回Set實例的成員總數。
- 實例方法:
add(value):添加某個值,返回set結構本身
delete(value):刪除某個值,返回布爾值,表示是否刪除成功。
has(value): 返回一個布爾值,表示是否爲Set成員。
clear():清除所有成員,沒有返回值。

3 . 遍歷操作:
keys(),values(),entries(),forEach()
由於Set結構沒有鍵名,只有鍵值(或者說鍵名和鍵值是同一個值),所以key方法和value方法的行爲完全一致。

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"]

Set結構的實例默認可遍歷,它的默認遍歷器生成函數就是它的values方法。這意味着,可以省略values方法,直接用for…of循環遍歷Set。

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

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

WeakSet
weakSet與Set類似,也是不重複的值的集合,區別:
1. WeakSet成員只能是對象
2. WeakSet對象都是弱引用,即垃圾回收機制不考慮WeakSet對該對象的引用,如果其他對象不再引用這個對象,那麼垃圾回收機制將自動回收該對象所佔內存。這意味着無法引用WeakSet的成員,因此WeakSet不可遍歷。

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

WeakSet可以接受一個數組或類似數組的對象作爲參數。該數組的所有成員,都會自動成爲WeakSet實例對象的成員。因此:數組的成員只能是對象。

原型方法:

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

Map
Map類似於對象,也是鍵值對的集合,但是“鍵”不限於字符串,各種類型的值都可以當鍵。
1 . 接受對象作爲鍵值

    var m=new Map();
    var o={p:"hello world"};

    m.set(o,"content");
    m.get(o);// "content"
    m.has(o) // true
    m.delete(o) // true
    m.has(o) // false

2 . 接受數組作爲參數,數組成員是一個個表示鍵值對的數組。

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

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

只有對同一個對象的引用,Map結構纔將其視爲同一個鍵。

var map = new Map();

map.set(['a'], 555);
map.get(['a']) // undefined

實例屬性和操作方法:
(1)size屬性
(2)set(key, value)
(3)get(key)
(4)has(key)
(5)delete(key)
(6)clear()
遍歷方法:
keys():返回鍵名的遍歷器。
values():返回鍵值的遍歷器。
entries():返回所有成員的遍歷器。
forEach():遍歷Map的所有成員。

12 . Iterator和for…of循環
遍歷器(Iterator)是一種接口,爲各種不同數據結構提供統一訪問機制。任何數據只要部署Iterator接口,就可以完成遍歷操作。
作用:
1. 提供統一的訪問接口
2. 使數據結構的成員按照某種次序排列
3. 創造了新的遍歷命令for…of循環,Iterator接口主要供for…of消費。

13 . Generator函數

function * foo(x, y) { ··· }

Generator函數是一個普通函數,有兩個特徵:
1. function關鍵字和函數名之間有一個*號
2. 函數體內部,使用yield語句,定義不同內部狀態。如果有多條yield語句,可以遍歷然後輸出

Generator函數調用同樣加圓括號,但是調用後並不執行,必須調用遍歷器對象的next方法,才執行,遇到yield語句,暫停,直到遇到下個next方法恢復執行,一直執行到return語句,遍歷結束,done屬性爲true.

1 . yield語句
Generator函數也可以省略yield,即變成一個單純的暫緩執行函數。

function* f() {
  console.log('執行了!')
}

var generator = f();

setTimeout(function () {
  generator.next()
}, 2000);
  1. yield語句不能再普通函數中調用。
  2. yield語句如果用在一個表達式之中,必須放在圓括號裏面。

for…of循環可以自動遍歷Generator函數生成的Iterator對象,此時不再需要調用next方法。

14 . Promise
Promise是一個對象,可以獲取異步操作的消息。
Promise狀態:
pending, resolved, rejected
只有異步操作的結果,可以決定當前是哪種狀態,任何其他操作都無法改變這個狀態。

基本用法

 var promise=new Promise(function(resolve,reject){
       //...some code

       if(/*異步操作成功*/){
           resolve(value)
       }else{
           reject(error)
       }
   })

Promise 構造函數接受一個函數作爲參數,該函數兩個參數分別是resolvereject,是兩個函數。由js引擎提供。
resolve函數作用:將Promise對象的狀態從“pending”變“resolved”,在異步操作成功時調用,並將異步操作結果傳遞出去。
reject函數作用:將狀態由“pending”變“reject”,失敗時調用,並將錯誤作爲參數傳遞出去。
Promise實例生成後,可以用then方法分別制定resolved,reject狀態的回調函數。

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

實例:

   var proTimer=function(){
      return new Promise(function(resolve,reject){
          setTimeout(function(){
              if(test>100){
                  resolve("成功")
              }else{
                  reject("失敗")
              }
          },1200)

   })};
//proTimer異步函數執行後,promise狀態改變,會立即出發then方法綁定的回調函數。
    proTimer().then(function(value){
        log(value)
    },function(err){
        log(err)
    });

Promise.prototype.then()
then方法返回的是一個新的promise實例,因此可以採用鏈式寫法,then後面再調用then, 第一個回調函數完成後,會將返回結果作爲參數傳遞給第二個then回調函數。

Promise.prototype.catch()
Promise.prototype.catch方法是.then(null, rejection)的別名,用於指定發生錯誤時的回調函數。

getJSON("/posts.json").then(function(posts) {
  // ...
}).catch(function(error) {
  // 處理 getJSON 和 前一個回調函數運行時發生的錯誤
  console.log('發生錯誤!', error);
});

一般來說,不要在then方法裏面定義Reject狀態的回調函數(即then的第二個參數),總是使用catch方法。
跟傳統的try/catch代碼塊不同的是,如果沒有使用catch方法指定錯誤處理的回調函數,Promise對象拋出的錯誤不會傳遞到外層代碼,即不會有任何反應。但chrome瀏覽器不遵守這條規定,會拋出錯誤。

promise.all()
用於將多個Promise實例,包裝成一個新的promise實例

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

Promise.all方法的參數必須有iterator接口,且返回的每個成員都是promise實例。

p的狀態由p1、p2、p3決定,分成兩種情況。

(1)只有p1、p2、p3的狀態都變成fulfilled,p的狀態纔會變成fulfilled,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回調函數。

(2)只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。

Promise.race()

Promise.race同樣將多個promise實例包裝成一個新實例。

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

不同的是,只要任一個實例率先改變,p的狀態就跟着改變。率先改變的promise實例的返回值就傳遞給p的回調函數。

Promise.resolve()
將現有對象轉換爲Promise對象。

Promise.resolve("foo")
//等價於
new Promise(resolve=>resolve("foo"))

Promise.resolve方法參數分爲四種情況:
1. 參數是一個promise實例:那麼不做任何修改,返回這個實例。
2. 參數是一個thenable對象,指具有then方法的對象。

let thenable={
then:function(resolve,reject){...
.)}

Promise.resolve會將這個對象轉換爲promise對象,然後立即執行thenable對象的then方法。
3. 參數不是具有then方法的對象,或者不是對象。
promise.resolve返回一個新的promise對象,狀態爲resolved.

var p = Promise.resolve('Hello');

p.then(function (s){
  console.log(s)
});
// Hello

4 . 不帶參數:直接返回一個resolved狀態的promise對象。立即resolve的promise對象,是在本輪“事件循環”結束時,setTimeout是在下一次事件循環開始時。

Promise.reject()
Promise.reject(reason)也會返回一個promise實例,實例狀態爲rejected.

部署done(), finally()方法

done()
保證拋出任何可能出現的錯誤。

 Promise.prototype.done=function(onFullfilled,onRejected){
        this.then(onFullfilled,onRejected)
                .catch(function(reason){
                    setTimeout(()=>{throw reason},0)
                })
    }

finally()
finally方法用於指定不管promise對象最後狀態如何,都會執行的操作,接受一個普通的回調函數作爲參數,該函數不管怎樣都必須執行。

 Promise.prototype.finally=function(callback){
        let P=this.constructor;
        return this.then(
                value => P.resolve(callback()).then(()=>value),
        reason=>P.resolve(callback()).then(()=>{throw reason})
        )
    }

15 . 異步操作和Async函數
異步編程的實現:

回調函數:

fs.readFile('/etc/passwd', function (err, data) {
  if (err) throw err;
  console.log(data);
});

Promise:將回調函數的嵌套修改成鏈式調用。

Generator函數

協程:多個線程相互協作,完成異步任務
運行流程如下:
第一步,協程A開始執行。
第二步,協程A執行到一半,進入暫停,執行權轉移到協程B。
第三步,(一段時間後)協程B交還執行權。
第四步,協程A恢復執行。
協程A就是異步任務,它分兩段或多段執行
寫法如下:

   function * asyncJob(){
       //...其他代碼
       var f=yield readFile(fileA);//執行到此處,執行權轉讓出去,等到執行權返回後,再從這繼續往後執行
       //...其他代碼
   }

Generator函數調用next()方法可以繼續執行任務。

Generator函數的數據交換和錯誤處理:
next():返回的值是Generator函數向外輸出的數據,next()還可以接受參數,進而傳入到Generator函數,作爲上個階段任務的返回結果。

function* gen(x){
  var y = yield x + 2;
  return y;
}

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

Generator函數內部還可以部署錯誤處理代碼,捕獲函數體外拋出的錯誤:

function* gen(x){
  try {
    var y = yield x + 2;
  } catch (e){
    console.log(e);
  }
  return y;
}

var g = gen(1);
g.next();
g.throw('出錯了');
// 出錯了

異步任務的封裝:

    var fetch=require("node-fetch");

    function * gen(){
        var url = 'https://api.github.com/users/github';
        var result = yield fetch(url);
        console.log(result.bio);
    }

    var g=gen();
    var result= g.next();
    result.value.then(function(data){
        return data.json();
    }).then(function(data){
        g.next(data)
    })

Thunk函數的含義
參數求值策略:
1. 傳值調用:進入函數體之前,就計算好參數的值
2. 傳名調用:進入函數體之後,用到該參數的時候,計算該參數的值。
傳名調用的實現,即將參數放到一個臨時函數中,再將這個臨時函數傳入函數體,這個臨時函數成爲Thunk函數。

function f(m){
  return m * 2;
}

f(x + 5);

// 等同於

var thunk = function () {
  return x + 5;
};

function f(thunk){
  return thunk() * 2;
}

JS中也是傳值調用,但是它的thunk函數替換的不是表達式,而是多參數函數,將其替換成單參數版本,且只接受回調函數作爲參數。

Async函數
1. async函數返回一個promise對象
async函數內部,return語句返回的值,會成爲then方法回調函數的參數。
2. async函數返回Promise對象,必須要等到內部所有await命令的promise對象執行完,纔會發生狀態改變。
3. 正常情況下,await命令後面是一個promise對象,如果不是,會調用Promise.resolve()轉換成promise對象。

await命令後面的Promise對象如果變爲reject狀態,reject的參數會被catch方法的回調函數接收到。
只要一個await的promise變爲reject,那麼整個async函數都會中斷執行。
eg.

async function f() {
  await Promise.reject('出錯了');
  await Promise.resolve('hello world'); // 不會執行
}

爲避免這個問題,兩種解決方法:
1. 放在try…catch結構裏

async function f() {
  try {
    await Promise.reject('出錯了');
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}

f()
.then(v => console.log(v))
// hello world
  1. await後面promise對象再跟一個catch

async function f() {
await Promise.reject('出錯了')
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// 出錯了
// hello world

如果有多個await命令,可以統一放在try…catch結構中

4 . 如果await後面的異步操作出錯,那麼等同於async函數返回的promise對象被reject.

注意點

  1. 最好把await命令放在try…catch代碼塊中
  2. 多個await命令後面的異步操作,如果不存在繼發關係,最好讓它們同時觸發。

繼發:

let foo = await getFoo();
let bar = await getBar();

同時觸發:

// 寫法一
let [foo, bar] = await Promise.all([getFoo(), getBar()]);

// 寫法二
let fooPromise = getFoo();
let barPromise = getBar();
let foo = await fooPromise;
let bar = await barPromise;

3 . await只能用在async函數中,用在普通函數中會報錯,例如forEach裏不能用await.可以使用for循環。

16. Class類
ES6引入class概念,通過class關鍵字定義類。

//定義類
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {//定義在prototype原型上的方法
    return '(' + this.x + ', ' + this.y + ')';
  }
}

定義類的方法的時候,不需要function關鍵字,直接定義函數就可以,方法之間不需要都好分隔,否則會報錯。

使用類,也是用new命令,跟構造函數用法一致。

可以使用Object.assign()一次性向類添加多個原型方法:

class Point{
    constructor(){
        //...
    }
}
    Object.assign(Point.prototype,{
        toString(){},
        toValue(){}
    })

類內部定義的所有方法,都是不可枚舉的。

  1. constructor方法:生成實例自動調用該方法,如果沒有顯示定義,會默認添加一個空的constructor(){}, 默認返回實例對象,也可以改寫。
  2. 不存在變量提升。
  3. 類也可以用表達式的形式定義。
const MyClass = class Me {
  getClassName() {
    return Me.name;
  }
};
//使用表達式定義了一個類。需要注意的是,這個類的名字是MyClass而不是Me,Me只在Class的內部代碼可用,指代當前類。如果內部沒有用到Me,可以省略Me,即:
const MyClass=class {//....}

4 . 私有方法:
es6不提供私有方法,可以在模塊外定義私有方法,然後模塊內部調用bar.call(this,baz),這就使得bar成爲當前模塊的私有方法。
5 . this指向:默認指向類的實例,

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章