ES6基礎筆記

1、解構賦值的使用場景

  • 交換變量的值
[x, y] = [y, x];
  • 方便從函數取值
function func() { return [1, 2, 3]; } var [a, b, c] = func();
  • 函數參數的定義
// 參數是一組無次序的值 function f({x, y, z}) { ... } f({z: 1, y: 2, x: 3});
  • 提取JSON數據
`var jsonData = { id: 12, name: "sss", data: [867, 5309] }; let { id, name, data: number } = jsonData;`
  • 函數默認參數值 
function move({x = 1, y = 2} = {}) { // 默認值 return [x, y]; } move({x: 3}); // y使用默認值,x:3, y:2

2、let與const

  1. let命令所在的代碼塊內有
  2. let不存在變量提高
  3. let 暫時性死區
  4. let 不能重複聲明同個變量

const 聲明一個只讀的常量。const聲明的常量不能從新賦值。編程

3、Symbol

常量使用Symbol值最大的好處,就是其餘任何值都不可能有相同的值了
Symbol.for方法能夠從新使用同一個Symbol值。
對象的屬性名如今能夠有兩種類型,一種是原來就有的字符串,另外一種就是新增的Symbol類型json

JavaScript只有indexOf方法,能夠用來肯定一個字符串是否包含在另外一個字符串中。ES6又提供了三種新方法。數組

  • includes():返回布爾值,表示是否找到了參數字符串。
  • startsWith():返回布爾值,表示參數字符串是否在源字符串的頭部。
  • endsWith():返回布爾值,表示參數字符串是否在源字符串的尾部。
`var s = 'Hello world!'; s.startsWith('Hello') // true s.endsWith('!') // true s.includes('w') // true`

4、ES6數組拓展

Array.from方法用於將兩類對象轉爲真正的數組promise

var arr= { '0': 'a', '1': 'b', '2': 'c', length: 3 }; // ES6的寫法 var arr2 = Array.from(arr); // ['a', 'b', 'c']

Array.of方法用於將一組值,轉換爲數組。若是沒有參數,就返回一個空數組。瀏覽器

Array.of(7, 8, 9) // [7,8,9] Array.of(13) // [13] Array.of() // [] Array.of(13).length // 1

5、箭頭函數

箭頭函數this對象指向
普通函數this 的指向服務器

  • js中的this是執行上下文,在普通函數中,this指向它的直接調用者;
  • 在默認狀況下(非嚴格模式),在全局環境下,js中的this指向window;

箭頭函數的this指向數據結構

箭頭函數體內的this對象就是定義時所在的對象,而不是使用時所在的對象。app

簡單而言,箭頭函數使用時,不綁定this對象,箭頭函數沒有本身的this,它的this是繼承而來的,默認指向在定義箭頭函數時所處的對象。異步

function foo() { return () => { return () => { return () => { console.log('id:', this.id); }; }; }; } 
var f = foo.call({id: 1}); // 設置foo的id爲1
var t1 = f.call({id: 2})()(); // id: 1 
var t2 = f().call({id: 3})(); // id: 1 
var t3 = f()().call({id: 4}); // id: 1

上面代碼之中,只有一個this,就是函數foo的this。因此t一、t二、t3都輸出一樣的結果。async

由於全部的內層函數都是箭頭函數,都沒有本身的this,它們的this其實都是最外層foo函數的this。因此箭頭函數的this指向是建立它所在的對象,不會改變。

箭頭函數有幾個使用注意點:

(1)函數體內的this對象,就是定義時所在的對象,而不是使用時所在的對象。

(2)不能夠看成構造函數,也就是說,不可使用new命令,不然會拋出一個錯誤。

(3)不可使用arguments對象,該對象在函數體內不存在。若是要用,能夠用Rest參數代替。

(4)不可使用yield命令,所以箭頭函數不能用做Generator函數。

6、rest參數

ES6引入rest參數(形式爲「...變量名」),用於獲取函數的多餘參數,這樣就不須要使用arguments對象了。rest參數搭配的變量是一個數組,該變量將多餘的參數放入數組中。

function add(...values) 
{ let sum = 0; 
for (var num of values) { sum += num; } 
return sum; } 
add(4, 5, 6,7) // 22

注意,rest參數以後不能再有其餘參數(即只能是最後一個參數),不然會報錯。函數的length屬性,不包括rest參數。

7、ES6屬性的遍歷

ES6一共有5種方法能夠遍歷對象的屬性:

  • for...in

    for...in循環遍歷對象自身的和繼承的可枚舉屬性(不含Symbol屬性)。

  • Object.keys(obj)

    Object.keys返回一個數組,包括對象自身的(不含繼承的)全部可枚舉屬性(不含Symbol屬性)。

  • Object.getOwnPropertyNames(obj)

    Object.getOwnPropertyNames返回一個數組,包含對象自身的全部屬性(不含Symbol屬性,可是包括不可枚舉屬性)。

  • Object.getOwnPropertySymbols(obj)

    Object.getOwnPropertySymbols返回一個數組,包含對象自身的全部Symbol屬性。

  • Reflect.ownKeys(obj)

    Reflect.ownKeys返回一個數組,包含對象自身的全部屬性,無論是屬性名是Symbol或字符串,也無論是否可枚舉。

以上的5種方法遍歷對象的屬性,都遵照一樣的屬性遍歷的次序規則。

  • 首先遍歷全部屬性名爲數值的屬性,按照數字排序。
  • 其次遍歷全部屬性名爲字符串的屬性,按照生成時間排序。
  • 最後遍歷全部屬性名爲Symbol值的屬性,按照生成時間排序。

8、class類

class關鍵字建立一個類代碼以下:

class Person{ constructor(x, y) 
{ this.x = x; this.y = y; } // 方法之間不加逗號隔開,不然報錯
sum(){ // 方法前面不用加function var sum=this.x+this.y; return sum } }

上面代碼定義了一個「類」,能夠看到裏面有一個constructor方法,這就是構造方法,經過new命令生成對象實例時,自動調用該方法。而this關鍵字則表明實例對象。

構造函數的prototype屬性,在ES6的「類」上面繼續存在。全部的方法仍是在prototype屬性上。

類的方法內部若是含有 this,它默認指向類的實例。

9、Map與Set數據結構

ES6提供了新的數據結構Set。它相似於數組,可是成員的值都是惟一的,沒有重複的值。

var set = new Set([1, 2, 3, 3, 4, 4]);
set   // Set { 1, 2, 3, 4 }

上面代碼能夠發現,定義的set對象會本身去除重複的值。Set表示數據的類型是Set。

由於Set數據值的惟一性,咱們能夠用它來對數組進行去重。代碼以下

var arr=[1, 2, 2, 3, 4, 4]; // 定義一個數組 
var set = new Set(arr); //使用擴展運算符Set結構轉爲數組 
var newArr=[...set]; // 或者使用Array.from方法將Set結構轉爲數組 var newArr=Array.from(set);
newArr // [1, 2, 3, 4]

Set實例的方法分爲兩大類:操做方法(用於操做數據)和遍歷方法(用於遍歷成員)
下面先介紹四個操做方法。

  • add(value):添加某個值,返回Set結構自己。
  • delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。
  • has(value):返回一個布爾值,表示該值是否爲Set的成員。
  • clear():清除全部成員,沒有返回值。
var s=new Set(); // 定義s 數據類型爲
Set s.add(1).add(2).add(2); // 使用add方法添加值,重複值不會被添加 
s.size // 2 注意2被加入了兩次,可是去重了一個,因此s的成員數是2 
s.has(1) // true 使用has方法判斷是否有該值,有因此返回true 
s.has(2) // true
s.has(3) // false  沒有該值返回
false s.delete(2); // 使用delete刪除該值 
s.has(2) // false 由於2被上面刪除了,因此沒該值,返回false

Set結構的實例有四個遍歷方法,能夠用於遍歷成員。Set的遍歷順序就是插入順序。

  • keys():返回鍵名的遍歷器。
  • values():返回鍵值的遍歷器,能夠省略。
  • entries():返回鍵值對的遍歷器。
  • forEach():使用回調函數遍歷每一個成員,它的參數是函數。

Map數據結構解決了傳統對象只能用字符串看成鍵的侷限性。

Map結構的實例屬性和操做方法以下:

(1)size屬性

    size屬性返回Map結構的成員總數。

(2)set(key, value)

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

(3)get(key)

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

(4)has(key)

    has方法返回一個布爾值,表示某個鍵是否在Map數據結構中。

(5)delete(key)

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

(6)clear()

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

使用方法以下:

var map=new Map();
map.set('foo', true); // 設置 
map.size; // 1
map.get('foo'); // true 
map.has('foo') // true 
map.delete('foo'); // 刪除map對象的foo鍵,刪除後使用has返回false 
map.clear() // 刪除map對象全部的鍵

Map其餘方法

Map原生提供三個遍歷器生成函數和一個遍歷方法。

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

遍歷方法和Set的差很少。

數據結構的互相轉換

(1)Map轉爲數組

前面已經提過,Map轉爲數組最方便的方法,就是使用擴展運算符(...)。
[...myMap] // myMap表示Map數據

(2)數組轉爲Map

將數組轉入Map構造函數,就能夠轉爲Map。

new Map(數組)

(3)Map轉爲對象

若是全部Map的鍵都是字符串,它能夠轉爲對象。

// Map轉對象函數 
function cMapToObj(strMap)
{ let obj = Object.create(null); 
for (let [k,v] of strMap)
{ obj[k] = v; } 
return obj; 
}
cMapToObj(myMap)

(4)對象轉爲Map

function objToMap(obj) { let strMap = new Map(); 
for (let k of Object.keys(obj))
{ strMap.set(k, obj[k]); } 
return strMap; }
objToMap(對象)

(5)Map轉爲JSON

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

JSON.stringify(cMapToObj(myMap)) // cMapToObj是上面定義的函數

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

JSON.stringify([...myMap])

(6)JSON轉爲Map

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

objToMap(JSON.parse( json數據 )) // objToMap是上面定義的函數

10、Proxy

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

下面是常見的 Proxy 支持的攔截操做方法。

(1)get(target, propKey, receiver)

    攔截對象屬性的讀取,好比proxy.foo和proxy['foo']。

    最後一個參數receiver是一個對象,可選,參見下面Reflect.get的部分。

(2)set(target, propKey, value, receiver)

    攔截對象屬性的設置,好比proxy.foo = v或proxy['foo'] = v,返回一個布爾值。

(3)has(target, propKey)

    攔截propKey in proxy的操做,以及對象的hasOwnProperty方法,返回一個布爾值。

(4)deleteProperty(target, propKey)

    攔截delete proxy[propKey]的操做,返回一個布爾值。

(5)apply(target, object, args)

    攔截 Proxy 實例做爲函數調用的操做,好比proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。

(6)construct(target, args)

    攔截 Proxy 實例做爲構造函數調用的操做,好比new proxy(...args)。

get()

get方法用於攔截某個屬性的讀取操做。上文已經有一個例子,下面是另外一個攔截讀取操做的例子。

var person = { name: "jack" }; 
var proxy = new Proxy(person, { 
get: function(target, property) { 
if (property in target) 
{ return target[property]; }
else { throw new ReferenceError("Property \"" + property + "\" does not exist."); } } }); 
proxy.name // "jack" 
proxy.age // 拋出一個錯誤

上面代碼表示,若是訪問目標對象不存在的屬性,會拋出一個錯誤。若是沒有這個攔截函數,訪問不存在的屬性,只會返回undefined。

set()

set方法用來攔截某個屬性的賦值操做。

let obj = { 
  set: function(obj, prop, value) { 
  if (prop === 'age') { 
  if (!Number.isInteger(value)) {
  throw new TypeError('錯誤信息:不是整數'); } 
  if (value > 200) {
  throw new RangeError('錯誤信息:年齡大於200'); 
    } 
   } 
// 對於age之外的屬性,直接保存 
obj[prop] = value; } }; 
let person = new Proxy({}, obj);
person.age = 13; person.age // 13
person.age = 'jack' // age不是整數報錯 
person.age = 300 // age大於200報錯

上面代碼中,因爲設置了存值函數set,任何不符合要求的age屬性賦值都會拋出一個錯誤。

11、Iterator接口

ES6創造了一種新的遍歷命令for...of循環。Iterator接口的目的,就是爲全部數據結構提供了一種統一的訪問機制,即for...of循環

Iterator的遍歷過程以下:

  1. 建立一個指針對象,指向當前數據結構的起始位置。也就是說,遍歷器對象本質上,就是一個指針對象。
  2. 第一次調用指針對象的next方法,能夠將指針指向數據結構的第一個成員。
  3. 第二次調用指針對象的next方法,指針就指向數據結構的第二個成員。
  4. 不斷調用指針對象的next方法,直到它指向數據結構的結束位置。

return方法的使用場合是,若是for...of循環提早退出(一般是由於出錯,或者有break語句或continue語句),就會調用return方法。若是一個對象在完成遍歷前,須要清理或釋放資源,就能夠部署return方法,注意,return方法必須返回一個對象,這是Generator規格決定的。

數組遍歷語法的比較

for循環

最原始的就是for循環

for(var i=0;i<10;i++){ console.log(i); }

forEach

數組提供內置的forEach方法,缺點是沒法中途跳出forEach循環,break命令或return命令都不能奏效。

myArray.forEach(function (value) { console.log(value); });

for...in

遍歷的是key。

缺點:數組的鍵名是數字,可是for...in循環是以字符串做爲鍵名「0」、「1」、「2」等等。

for...in循環主要是爲遍歷對象而設計的,不適用於遍歷數組。

for (let i of list) { console.log( i ); }

for...of

遍歷的是value。

for ...of 循環相比上面幾種作法,有一些顯著的優勢。

  • 有着同for...in同樣的簡潔語法,可是沒有for...in那些缺點。
  • 不一樣用於forEach方法,它能夠與break、continue和return配合使用。
  • 提供了遍歷全部數據結構的統一操做接口。
for (var n of list ) { if (n > 1000) break; console.log(n); }

var list=[1,3,"a","b",6];

代碼1

for( var i in list){     console.log(i) }

代碼2

for(var  i of list){     console.log(i) }

代碼1依次輸出結果的是:0 1 2 3 4

代碼2依次輸出的結果是:1 3 a b 6

12、Promise、async異步函數

Promise是爲了解決多重嵌套回調函數而提出的它不是新的語法功能,而是一種新的寫法,容許將回調函數的嵌套,改爲鏈式調用。從語法上說,Promise是一個對象,從它能夠獲取異步操做的消息。

Promise提供統一的API,各類異步操做均可以用一樣的方法進行處理

Promise有如下兩個特色:

  • 對象的狀態不受外界影響。Promise對象表明一個異步操做,有三種狀態:Pending(進行中)、Resolved(已完成,又稱Fulfilled)和Rejected(已失敗)。
  • 一旦狀態改變,就不會再變,任什麼時候候均可以獲得這個結果。Promise對象的狀態改變,只有兩種可能:從Pending變爲Resolved和從Pending變爲Rejected。只要這兩種狀況發生,狀態就凝固了,不會再變了,一直保持這個結果。

Promise也有一些缺點:

  • 沒法取消Promise,一旦新建它就會當即執行,沒法中途取消。
  • 若是不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。
  • 當處於Pending狀態時,沒法得知目前進展到哪個階段(剛剛開始仍是即將完成)。

ES6規定,Promise對象是一個構造函數,用來生成Promise實例。

Promise構造函數接受一個函數做爲參數,該函數的兩個參數分別是resolve和reject。它們是兩個函數,由JavaScript引擎提供,不用本身部署。

下面代碼創造了一個Promise實例。

var promise = new Promise(function(resolve, reject) {
if (true){ 
resolve(value); 
} 
else { reject(error); }
});

resolve函數的做用是,將Promise對象的狀態從「未完成」變爲「成功」(即從Pending變爲Resolved),在異步操做成功時調用並將異步操做的結果,做爲參數傳遞出去。

**reject函數的做用是,將Promise對象的狀態從「未完成」變爲「失敗」(即從Pending變爲Rejected),在異步操做失敗時調用並將異步操做報出的錯誤,做爲參數傳遞出去。
**
then方法

Promise實例具備then方法。

then方法返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。所以能夠採用鏈式寫法,即then方法後面再調用另外一個then方法。

catch方法

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

`getJSON("/posts.json") .then(function(posts) {}) .catch(function(error) {console.log('發生錯誤!', error); });`

`

上面代碼中,getJSON方法返回一個Promise對象,若是該對象狀態變爲Resolved,則會調用then方法指定的回調函數;若是異步操做拋出錯誤,狀態就會變爲Rejected,就會調用catch方法指定的回調函數來處理這個錯誤。另外,then方法指定的回調函數,若是運行中拋出錯誤也會被catch方法捕獲。

p.then((val) => console.log("fulfilled:", val)) .catch((err) => console.log("rejected:", err)); // 等同於 p.then((val) => console.log("fulfilled:", val)) .then(null, (err) => console.log("rejected:", err));

ES6誕生之前,異步編程的方法,常見的有下面四種。

  • 回調函數
  • 事件監聽
  • 發佈/訂閱
  • Promise 對象

ES6將JavaScript異步編程帶入了一個全新的階段,ES7的Async函數更是提出了異步編程的新解決方案

async函數

ES7提供了async函數,使得異步操做變得更加方便。

async函數是什麼?
async函數就是Generator函數的語法糖。

 語法      async function name(param) { statements }

  • name: 函數名稱。
  • param: 要傳遞給函數的參數名稱。
  • statements: 函數體。

返回值

async 函數返回一個 Promise 對象,可使用 then 方法添加回調函數。

async函數內部return語句返回的值,會成爲then方法回調函數的參數。

async function foo(){
return "這是async函數的返回值"; 
} 
console.log(foo()) // Promise { '這是async函數的返回值' } 
foo().then((args)=>{ // 回調函數是箭頭函數 
console.log(args); // 這是async函數的返回值 
})

await命令

await操做符用於等待一個 Promise 對象, 它只能在異步函數 async function 內部使用。

await 的返回值

  • 若是一個 Promise 被傳遞給一個 await 操做符,await 將等待 Promise 正常處理完成並返回其處理結果。
function testAwait (x) { 
return new Promise(resolve => {
setTimeout(() => { 
resolve(x);
}, 2000); 
});
}
async function foo() { 
var x = await testAwait ("hello world");
console.log(x); 
} 
foo (); // hello world
  • 正常狀況下,await命令後面是一個Promise對象。若是不是,會被轉成一個已完成狀態的Promise對象。

async function f() { return await 123; } f().then(v => console.log(v)) // 123

async函數返回的Promise對象,必須等到內部全部await命令的Promise對象執行完纔會發生狀態改變。也就是說,只有async函數內部的異步操做執行完纔會執行then方法指定的回調函數。

async函數的錯誤處理

若是await後面的異步操做出錯,那麼等同於async函數返回的Promise對象被reject。

async function f() {
await new Promise(function (resolve, reject) {
throw new Error('出錯了111'); 
}); 
} 
f() .then(v => console.log(v)) .catch(e => console.log(e)) // Error:出錯了111

上面代碼中,async函數f執行後,await後面的Promise對象會拋出一個錯誤對象,致使catch方法的回調函數被調用,它的參數就是拋出的錯誤對象。

防止出錯的方法,把await命令放在try...catch代碼塊中。

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

十3、ES6模塊化
ES6 以前,社區制定了一些模塊加載方案,最主要的有 CommonJS 和 AMD 兩種。前者用於服務器,後者用於瀏覽器

ES6 在語言標準的層面上,實現了模塊功能,成爲瀏覽器和服務器通用的模塊解決方案

模塊功能主要由兩個命令構成:export 和 import。export命令用於規定模塊的對外接口,import命令用於輸入其餘模塊提供的功能。

使用export命令定義了模塊的對外接口之後,其餘 JS 文件就能夠經過import命令加載這個模塊。

注意,import命令具備提高效果,會提高到整個模塊的頭部,首先執行。

一個模塊就是一個獨立的文件。該文件內部的全部變量,外部沒法獲取。

若是你但願外部可以讀取模塊內部的某個變量,就必須使用export關鍵字輸出該變量。

相關文章
相關標籤/搜索