用簡單的方法學習ES6

ES6 簡要概覽

這裏是ES6 簡要概覽。本文大量參考了ES6特性代碼倉庫,請容許我感謝其做者@Luke Hoban的卓越貢獻,也感謝@Axel Rauschmayer所做的[優秀書籍]//exploringjs.com/es6/)。javascript

起初當我據說ES6時,我花了不少精力去消化學習其概念和基礎知識。我經歷了這些,但願大家無需重蹈覆轍。所以我寫下了這篇對ES6及其新特性的簡要介紹,全部知識點都解釋得通俗易懂,簡明扼要,對於像我這樣的新人很是友好。php

簡介

ES6,也稱做ECMAScript 2015,是JavaScript的下一代版本,在2015年6月正式標準化。ES6是該語言自2009年的ES5以來的一次重大更新。css

  • 這是一門全新的語言嗎?:絕對不是!它就是咱們所瞭解的JavaScript,只不過擁有了更優雅的語法和更多特性。
  • 這是否意味着我現有的JavaScript代碼不久就將變得不可用了?:並不是如此!若是是那樣的話,對整個網站將是巨大的損失!JavaScript一直都是向後兼容的。好比,新的特性將會被添加,而現存特性將會變得更強大。這叫作惟一的JavaScript
  • 它的目標是什麼?:整體來講是成爲了一門更好的語言!它讓咱們的代碼更快,更安全,更搞笑。
  • ES6以後還會有什麼?:會出現ECMAScript 7等等後續版本。TC39計劃每一年發佈一個ECMAScript的新版本。好比,從如今開始,ECMAScript版本將會做相對較小的升級。所以,當你想開始學ES7和後續版本時,你如今所學的關於ES6的一切將會派上用場。

安裝

這個部分是爲那些還不熟悉命令行的Web設計開發者準備的。若是你已經知道如何安裝node.js 和 Babeljs,以及ES6編譯器,你能夠跳過這部分。html

我是否須要安裝一些東西?是的!因爲ES6是新的,瀏覽器還沒有支持其大多數特性。但咱們無需等待。咱們能夠在node.js 和 Babeljs, 以及S6編譯器的幫助下開始編寫ES6代碼Babeljs將會將ES6語法轉換爲ES5,這樣現有的瀏覽器就能夠解釋咱們的代碼了,就好像咱們一開始就是用ES5編寫的同樣。這是否是很酷?讓咱們來看看全部這一套是如何安裝的,而後開始編寫代碼。java

  • 首先下載和安裝node.js到你的機器上。
  • 打開終端/命令行,輸入npm install --global babel。按下回車運行該命令,而後第一次安裝Babeljs到你的機器。Babeljs就是ES6的編譯器。
  • 運行命令: npm install -g browserify。若是你想使用ES6模塊加載器語法,須要把Browserify也裝上。Browserify使你能在獨立的JavaScript文件中編寫更加模塊化的代碼,而後將它們打包,最後讓你的HTML頁面只需引用一個JavaScript文件。
  • 運行命令:cd path/to/my/project,將路徑更改成你的項目路徑。
  • 運行命令:babel src --out-dir build。這條命令會將'src'文件夾下的全部 .js 後綴的文件從ES6轉換爲ES5語法,而後將轉換後的文件放入'build'目錄下。

如今你已經準備好了,你能夠將新的轉換後的.js文件引入你的HTML頁面,瀏覽器就能夠像往常同樣正常運行你的代碼。node

ES6 特性

字符串,數組,及對象的新增API

在ES6中,咱們有許多新增的庫,包括核心的Math庫,數組轉換幫助工具和用於拷貝的Object.assign()jquery

'hello'.startsWith('hell'); // => true 'hello'.endsWith('ello'); // => true 'hello'.includes('ell'); // => true 'doo '.repeat(3); // => 'doo doo doo ' Array.from(document.querySelectorAll("*")); // => 返回一個真實的數組 Array.of(1, 2, 3); // => 和 new Array(...)類似, 可是不須要指定單參數 [0, 0, 0].fill(7, 1); // => [0,7,7] [1, 2, 3].findIndex(x => x == 2); // => 1 ['a', 'b', 'c'].entries(); // => 迭代器 [0, 'a'], [1,'b'], [2,'c'] ['a', 'b', 'c'].keys(); // => 迭代器 0, 1, 2 ['a', 'b', 'c'].values(); // => 迭代器 'a', 'b', 'c' Object.assign(Point, { origin: new Point(0,0) }); // => 爲'Point'對象添加新屬性. 

Symbol

Symbol是ES6中的一種新的原始數據類型。它們是做爲獨有ID使用的字符。你能夠經過工廠函數Symbol()創造symbol字符。它們都是獨一無二的。每次咱們建立一個新的symbol,咱們其實是建立了一個新的獨一無二的標識符,它不會與咱們項目中其餘任何變量名、屬性名衝突。這就是爲何某些場景下它頗有用的緣由。例如,咱們可使用它定義一個常量。git

在ES5中,咱們之前會使用兩個不一樣的對無二的字符串來定義常量。咱們會不得不依賴於字符串!但衆所周知,字符串並不具有惟一性。咱們可能在偶然的時機改變它,或在不一樣的地方輸入它們,這些操做會使咱們的常量的行爲崩壞。可是如今,咱們能夠很容易地使用Symbol()來定義常量,並能確保每次咱們調用Symbol()時都會產生一個在咱們項目中獨一無二的標識符,而且永遠不會和其餘屬性名產生衝突。這很酷!es6

const COLOR_RED = Symbol(); const COLOR_ORANGE = Symbol(); console.log( 'each Symbol() is always unique: ', Symbol() === Symbol() ); // => 沒錯,這樣也會返回false. // 它也能夠幫咱們爲對象和類建立獨一無二的動態的方法。 const MY_KEY = Symbol(); let obj0 = {}; obj0[MY_KEY] = 123; console.log('my dynamic object method: ', obj0[MY_KEY]); // => 123 

擴展閱讀

模板字符串

模板字符串爲構造字符串提供了語法糖。字符串自己被撇號包裹,字符串中插入的表達式使用${var}分隔。模板字符串一般用來建立字符串。github

// 多行字符串
const HTML5_SKELETON = `
<!doctype html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> </body> </html>`; // 內嵌變量綁定 let name = 'Bob', time = 'today'; let greeting = `Hello ${name}, how are you ${time}?`; // 與標籤模板一塊兒使用,生成的原始字符串將包含模板字符串中的全部轉義字符和反斜槓。 let str = String.raw`This is a text with multiple lines. Escapes are not interpreted, \n is not a newline.`; 

擴展閱讀

Let + Const

ES6提供了兩種聲明變量的方式:let 和 const,它們幾乎替代了ES5中使用var聲明變量的方式。letvar的工做方式很像,可是它聲明的變量是有塊做用域的,它只在於當前的塊做用域中有效。而var聲明的變量是在函數做用域內有效。

function func(randomize) { if (randomize) { let x = Math.random(); // 注意:變量x只存在於這個if做用域中 var y = Math.random(); // 可是變量y能夠在整個func函數中訪問到 } // 塊做用域意思是:咱們能夠在一個函數中保護一個變量。好比,這裏的x與上述的x沒有任何關係。 let x = 5; return y; } 

const 和 let工做原理相似,可是你聲明變量的同時必須當即用一個不會再改變的值對其進行初始化。

const a = 123; 

注意const 陷阱!const只保證變量自身是永恆不變的,若是變量是一個對象,則其屬性仍然是可變的,相應的解決辦法就是JavaScript的 freeze() 方法。

const freezObj = Object.freeze({}); 

解構

解構容許咱們在支持匹配數組和對象的條件下,使用模式匹配進行綁定。 解構其實是一種從存儲於對象和數組(多是嵌套存儲)的數據中提取值的簡便方法。

// 讓咱們更好地理解解構: let obj1 = {}; obj1.first = 'Jane'; obj1.last = 'Doe'; // 這是咱們構造對象數據的方式 let f1 = obj1.first; let l1 = obj1.last; // 這是咱們從對象中提取數據的方式 // 咱們也可使用對象字面量來構造: let obj2 = { first: 'Jane', last: 'Doe' }; // 解構和它很相似。解構就是構造的對立面。它使咱們提取數據變得更加容易。 let { first: f2, last: l2 } = obj2; // 如今咱們得到了變量f2和l2。 // 解構對數組一樣適用 let [x1, y1] = ['a', 'b']; // => x1 = 'a'; y1 = 'b' // 用計算過的值做爲屬性 const FOO = 'foo'; let { [FOO]: f4 } = { foo: 123 }; // => f4 = 123 

咱們也可爲解構選擇一種模式。注意:值得一提的是,當咱們使用解構賦值時,咱們須要聲明要從數組或對象中抽取的變量。好比,在下面的例子中,咱們要從obj3中抽取foo,並將其存儲爲變量f3。咱們只建立了訪問對象的foo屬性的模式,而且只聲明瞭該屬性,由於咱們只須要用到它。

let obj3 = { a: [{ foo: 123, bar: 'abc' }, {}], b: true }; let { a: [{foo: f3}] } = obj3; // => f3 = 123 

解構賦值也能夠有默認值:

let [x3 = 3, y3] = []; // => x3 = 3; y3 = undefined let {foo: x4 = 3, bar: y4} = {}; // => x4 = 3; y4 = undefined // 固然,默認值也能夠是函數(執行的結果 -- 譯者注): function log() { return 'YES' } let [aa=log()] = []; // Default values can refer to other variables in the pattern.默認值能夠指向模式中的其餘變量,但它們的順序相當重要!如下寫法會產生引用錯誤: // let [x=y, y=3] = []; // 爲何呢?由於當x指定y爲其默認值時,y尚未被定義。 let [xx=3, yy=xx] = []; 

解構也能夠用於for...of循環。**注意: **在ES6中有一種新型的循環,for...of。在ES5以前,當咱們想要遍歷一個數組時,會使用for,ES5中有一個forEach()方法幫助咱們達成目的。如今的for...of更易用。

// 使用for...of循環數組示例 let arr = ['a', 'b', 'c']; for ( let item of arr ) { //console.log(item); } // 經過使用新的數組方法 entries()和解構賦值,咱們能夠獲得數組中每一個元素的索引和值。 for ( let [index, item] of arr.entries() ) { //console.log(index + '. ' + item); } // 也可使用下面的方法實現 for ( {name: n, age: a} of arr ) { // do something } // 數組模式對可迭代對象都有效 let [x2,...y2] = 'abc'; // => x2='a'; y2=['b', 'c']; 展開運算符'rest' let [,,x] = ['a', 'b', 'c', 'd']; // => x = 'c'; 能夠省略元素 

好,那麼除此以外,解構賦值還能用於哪些場景呢?

// 用於分割數組 let [first1, ...rest1] = ['a', 'b', 'c']; // 返回多個值 function testing() { return {element: undefined, index: -1}; } 

擴展閱讀

默認值和展開運算符

ES6提供了一個新的更好的定義函數參數默認值的方式:

// 在ES5中,你是這樣定義參數的默認值的: function foo(x, y) { x = x || 0; y = y || 0; // do something } // ES6用更好的語法來實現: function foo(x=0, y=0) { // y is 0 if not passed (or passed as undefined) } // 經過ES6,你能夠在定義參數時使用解構賦值,代碼會變得更簡潔: function selectEntries1({ start=0, end=-1, step=1 } = {}) { // do something } // 上述函數與這個等同: function selectEntries2(options) { options = options || {}; var start = options.start || 0; var end = options.end || -1; var step = options.step || 1; // do something } 

ES6也支持rest展開運算符:

function format(pattern, ...params) { return params; } format('a', 'b', 'c'); // ['b', 'c'] // params是一個數組 // ES6 中咱們有展開運算符'...'。 // 在ES5中,咱們使用apply()來將數組中的元素轉成參數。 Math.max.apply(null, [-1, 5, 11, 3]); // 如今,咱們很容易就能夠實現這個功能,由於展開運算符會提取它的每一項,而後將其轉換到參數中。 Math.max(...[-1, 5, 11, 3]); 

擴展閱讀

箭頭函數和this關鍵字

箭頭函數是使用=>語法簡寫的函數。可是與其餘函數不一樣的是,箭頭函數包裹的內部代碼共享同一個this關鍵字。

函數體是表達式:

var evens = [0,2,4]; // 如下兩種寫法效果相同: var odds = evens.map(v => v + 1); var odds = evens.map(function(v){ return v + 1; }); // 如下兩種寫法效果相同: var nums = evens.map((v, i) => v + i); var nums = evens.map(function(v, i){ return v + i; }); 

函數體是聲明:

var fives = []; nums.forEach(v => { // 看見了嗎,對於更復雜的聲明,咱們能夠把全部東西放進大括號{}中,就像咱們使用普通函數那樣。 if (v % 5 === 0) fives.push(v); }); 

關鍵字this:

var bob = { _name: 'Bob', _friends: [], printFriends() { this._friends.forEach(f => // 'this' 關鍵字就指向'bob'對象,而不是指向這個閉包做用域自己。 console.log(this._name + ' knows ' + f)); }, }; class UiComponent { constructor() { let button = document.getElementById('myButton'); button.addEventListener('click', () => { // 經過使用箭頭函數,'this'關鍵字就指向咱們的'UiComponent'類,而不是閉包。這是ES6提供的很棒的特性。在這種場景下,咱們不再須要使用bind()了。 this.handleClick(); }); } handleClick() { console.log('CLICK'); } } 

ES2015的類是一種基於原型的簡單語法糖。

class Person { // 當一個類初始化時,會自動調用構造函數。 constructor(fname, lname) { // 類內部只能包含方法,而不能包含屬性,所以咱們須要在構造函數內部設置咱們的屬性。 this.fname = fname; this.lname = lname; } } class Employee extends Person { constructor(fname, lname, name = 'no name') { // 在繼承類中,必須調用super()才能使用'this'關鍵字去定義屬性,好比this.name. 以及,若是咱們不調用super(),會獲得引用錯誤。 super(fname, lname); if (name === 'no name') this.name = this.fname + ' ' + this.lname; } setJob(title) { this.job = title; } static greeting() { return 'Hello World!'; } // 同時,類智能讓咱們建立靜態方法,而不能建立靜態數據屬性。可是咱們能夠建立一個靜態的getter函數。 static get JOHN() { return new Employee('John', 'Doe'); } // Getters and setters get prop() { return this.prop; } set prop(value) { this.prop = value; } // 計算事後的方法名 ['my'+'Method']() { // do something } } var john = new Employee('John', 'Doe'); john.setJob('Designer'); console.log('Class-> Employee class, just initialized: ', Employee.JOHN); console.log('Class-> Employee class, greeting: ', Employee.greeting()); console.log('Class-> John: ', john); 

擴展閱讀

加強的對象字面量

對象字面量被擴展以支持在構造時以foo: foo的簡寫形式設置原型,定義方法和調用上層函數。

let first = 'Jane'; let last = 'Doe'; let propKey = 'foo'; let obj = { // 方法的定義 myMethod(x, y) { // do something }, // 屬性值簡寫,以下: // let obj = { first, last }; // 效果同下: // let obj = { first: first, last: last }; first, last, // 計算後的屬性值: [propKey]: true, ['b'+'ar']: 123, ['h'+'ello']() { // console.log(obj.hello()); return 'hi'; }, // Setter和Getter函數 get sth() { console.log('Object Literal-> ', 'sth getter'); return 123; }, set sth(value) { console.log('Object Literal-> ', 'sth setter'); // 返回值被忽略 } }; // 對象中的新方法 // 對象中最重要的新方法就是assign(). Object.assign(obj, { bar: true }); // 它爲咱們的對象新增參數。 console.log('Object Literal-> ', JSON.stringify(obj)); // {"first":"Jane","last":"Doe","foo":true,"bar":true,"sth":123} 

迭代器與for..of循環

ES6 爲遍歷引入了新的接口,iterable(Iterable 實際上意味着任何東西均可以被重複)。數組,字符串,Map對象,Set對象,DOM數據結構(正在使用中的)都是可迭代的iterable對象。

所以,用簡單的話來講,迭代器就是一種結構,每次調用它時都會按序列返回下一個結果。例如數組的entries()方法。每次咱們調用arr.entries(),它都會返回數組中的下一項。

注意:有的可迭代結構並非什麼新鮮事情,例如for循環。可是,我這裏只是想解釋迭代協議是什麼,使它的概念更清晰,而且引入關於它的ES6新特性。

經過迭代協議接收數據的語言構造:

// 解構其實是在作迭代的工做(重複性的工做)來從數組中提取數據。完成這個目標是以一個特別的模式進行重複性的工做。 let [a,b] = new Set(['a', 'b', 'c']); // for-of顯然是可迭代的。 for (let x of ['a', 'b', 'c']) { console.log('for-of iteration-> ', x); } let arr2 = Array.from(new Set(['a', 'b', 'c'])); // => Array.from() let arr3 = [...new Set(['a', 'b', 'c'])]; // => 展開運算符 (...) let map0 = new Map([[false, 'no'], [true, 'yes']]); // => Maps的構造函數 let set0 = new Set(['a', 'b', 'c']); // => Sets的構造函數 // Promise.all(iterableOverPromises).then(); // Promise.all() // Promise.race(iterableOverPromises).then(); // Promise.race() // yield* 也是可迭代的 // 注意:當咱們想建立一個nGenerator函數時,'yield' 與Generators相關 // (Generator 是ES6中的新特性) 

讓咱們來使用迭代器:

let arr4 = ['a', 'b']; let iter = arr4[Symbol.iterator](); //咱們經過鍵爲Symbol.iterator的方法創造了一個迭代器 // 而後咱們重複調用迭代器的next()方法來檢索每一項。 // 在數組內部: iter.next(); // returns an object: { value: 'a', done: false } iter.next(); // { value: 'b', done: false } iter.next(); // { value: undefined, done: true } // 注意:布爾屬性'done'暗示了item序列是否到達了末尾。 

看見了嗎?這其實有一點像循環。它每次都返回一個新的東西。注意:迭代協議的一個關鍵特性就是它的有序性:迭代器自己每次只返回一個值,這意味着若是一個迭代的數據結構是非線性的(好比樹),迭代器會對其進行線性化。

如今,讓咱們在對象中使用Symbol,使其行爲表現像一個迭代器同樣:

let iterableObject = { // 咱們的對象必需要有一個動態方法,其實是這個動態方法在使用Symbol原始類型。正如咱們所知,Symbol老是獨一無二的,這也正是咱們的使用場景,利用它爲咱們的類建立一個獨一無二的動態方法。 [Symbol.iterator]() { let data = ['hello', 'world']; let index = 0; // 如今咱們的迭代器方法必須返回一個含有next()方法的對象 return { // Here is our iterator logic! In our example here, we check 'index' // variable and act accordingly based on its value.這就是咱們的迭代器邏輯!在這個例子中,咱們檢驗了'index'變量和基於它的值的表現。 next() { if (index < data.length) { return { value: data[index++] }; } else { return { done: true }; } } }; } }; // 這就是咱們如何使用迭代對象的方法。 for (let x of iterableObject) { // x每次都不一樣。第一次循環它是'hello',第二次是'world'. console.log('iterableObject-> ', x); } 

注意:正如咱們所知,咱們在對象中使用了symbol做爲方法的鍵名。這個獨一無二字符製造器使對象可迭代,而且使咱們可使用for...of循環。酷~如今咱們已經在咱們的代碼裏建立了一個定製的迭代對象(或類),這使咱們能夠在項目中是的迭代部分的代碼更簡單。

若是以上可迭代對象是一個真實的樣本,它可能在項目中很是有用。對我來講沒有必要把全部邏輯都放進for...of循環來作一個迭代的工做,我只須要建立一個有意義的可迭代類,而後把個人邏輯都放在其中,而後我就能夠在不一樣的地方用for...of循環使用個人類,而且能夠很簡單地實現迭代工做。很簡單吧~這將使個人代碼更簡潔。

擴展閱讀

模塊

組件定義中,對模塊的語言層面的支持。從流行的JavaScript模塊加載器(AMD, CommonJS)整理的模式。在ES6中,模塊存儲於文件。每一個文件都是一個模塊,每一個模塊也都是一個文件。

// lib/math.js // 咱們能夠從文件中導出任何變量或函數。 export function sum(x, y) { return x + y; } export var pi = 3.141593; // app.js // 從其餘文件中引入咱們想要的任何東西 import * as math from "lib/math"; // 如今,咱們能夠像下面這樣訪問咱們從math.js導出的任何東西: alert("2π = " + math.sum(math.pi, math.pi)); // otherApp.js // 咱們也能夠明確指明要引入的函數而不是用一個通用的名字。 import {sum, pi} from "lib/math"; alert("2π = " + sum(pi, pi)); 

也容許有一個單獨的默認輸出。Node.js社區中,有不少只導出一個值的模塊。咱們可讓模塊只導出一個類或函數。

// myFunc.js // 固然,咱們導出的函數也能夠有一個名稱:export default function foo() {} export default function() { } import myFunc from 'myFunc'; myFunc(); // MyClass.js // 以及咱們導出的函數固然也能夠有一個名稱: export default class Bar {} export default class { } import MyClass from 'MyClass'; let inst = new MyClass(); 

正如咱們所知,在 ES5代碼裏,不會經過庫(相似於RequireJS, Browserify 或 Webpack)來使用模塊,其模塊模式很是流行,是基於IIFE(當即執行函數)的。它的優勢就是明確將共有和私有部分區分開來了.

// 在ES5中如何合理建立模塊: // my_module.js var my_module = (function () { // 私有模塊的變量 var countInvocations = 0; function myFunc(x) { countInvocations++; } // 經過模塊導出: return { myFunc: myFunc }; }()); // 該模塊模式產生了一個全局變量,它的使用以下: my_module.myFunc(33); 

在ES6中,模塊是內建的,這就是爲何使用它們的門檻很是低的緣由:

// 如何在ES6中合理建立模塊: // my_module.js // 私有模塊的變量: let countInvocations = 0; // 導出模塊 export function myFunc(x) { countInvocations++; } 

擴展閱讀

四種數據結構:Map,Set,WeakMap,WeakSet

對於通用算法很高效的數據結構。接下來的四種數據結構是ES6中新增的:MapWeakMapSetWeakSet

Map ES5中缺失的是一種值到值的映射。ES6 的 Map數據結構讓你能使用任意值做爲鍵,非常一種很流行的作法。

// 建立一個空的Map let map = new Map(); // 咱們也能夠在初始化時就填充map爲其賦值: let map = new Map([ [ 1, 'one' ], [ 2, 'two' ] ]); // Map的set()方法時可鏈式調用的。所以咱們也能夠像這樣填充map賦值: let map = new Map().set(1, 'one').set(2, 'two'); // 任意值,甚至是一個對象,均可以做爲鍵。 // 若是咱們將要得到的值因爲某種緣由是undefined,那咱們也能夠設置或運算符:map.get(KEY) || 0; const KEY = {}; map.set(KEY, 123); map.get(KEY); // => 123 map.has(KEY); // => true map.delete(KEY); // => true map.size; // => 1 map.clear(); // => 清空map // keys()返回一個Map中的鍵可迭代的對象。好比咱們能夠在一個for-of循環中使用它。 map.keys(); // values() 返回一個Map中的值可迭代的對象。 map.values(); // 返回一個Map中的鍵值對[key,value]可迭代的對象。 // 注意:咱們能夠在for-of循環中使用解構,同時訪問到keys和values(鍵-值),就像咱們用數組的entries()方法能作的那樣。 map.entries(); 

WeakMap: 是一種防止其鍵被垃圾回收機制回收的Map。這意味着你能夠用對象協調數據而不須要擔憂內存泄漏。WeakMap是一種keys必須爲對象,值能夠爲任意值的數據結構。它有同Map同樣的API,惟一一點顯著差異是:你不能對內容進行迭代,不管是keyvalue,仍是entries。你也不能清除WeakMap

Set: Set也是 ES5 所沒有的數據結構。有兩種可能會用到 Set 的地方:

  • 使用對象的key去存儲字符串集合的元素。
  • 在數組中存儲任意的集合元素:經過indexOf()來檢驗是否包含某個元素,經過filter()刪除元素等等。這不是一個快速解決辦法,可是很容易實現。一個須要知曉的地方是,indexOf()沒法找出值爲NaN的元素。

ES6 的 Set 數據結構對任意值的操做而言很奏效,並且能正確處理NaN

let set = new Set(); // 咱們也能在初始化時就填充Set的值。 let set = new Set(['red', 'green', 'blue']); // Setadd()方法是可鏈式調用的。所以咱們能夠像這樣爲set賦值: let set = new Set().add('red').add('green').add('blue'); set.add('red'); set.has('red'); // => true set.delete('red'); // => true set.size; // => 1 set.clear(); // => 清空set

WeakSet: Set能夠防止其元素被垃圾回收機制回收。

注意: 爲何MapSet都是具有size屬性而不是像數組那樣用length屬性呢?這個不一樣之處的緣由在於length是對序列而言的,序列這種數據結構是有索引的,像數組這樣。size屬性是對於集合而言的,它們一般是無序的,像MapSet這樣。

擴展閱讀

Promise對象

Promise對象是用於異步編程的庫。咱們已經熟悉了JavaScript中的promise模式。可是在一些簡單場景下,它實際上使得異步的行爲更簡單。咱們能夠設置一個新的promise,在其中編寫任何一部行爲。好比ajax調用或timeout定時器等等。

function getJSON (url) { let promise = new Promise(function (resolve, reject) { // OK,如今咱們能夠在promise中編寫咱們的異步行爲代碼了。好比ajax調用。 // resolve(value); // 若是咱們的ajax調用成功,會調用resolve()並傳遞必要的參數給它。參數是什麼呢?由咱們本身根據咱們的異步工做而決定。 // 好比,對於ajax工做,jquery的ajax()方法在其成功加載文件後會調用咱們的成功回調函數。它也會傳遞一個參數,就是它實際加載的數據。 // 所以咱們這兒的參數就是這個數據。 // reject(error); // 若是失敗,咱們會調用reject(),而且傳遞必要的參數給它。 }); return promise; // r記得將promise返回 } // 這就是咱們使用promise的方式。 // 當promise狀態轉爲resolved時,它的then()方法將會被調用。當它的狀態轉爲rejected時,catch()方法將會被調用。 getJSON('promised.json') .then(value => {}) .catch(error => {}); // 注意:then()方法也有可選的第二個參數,實際上就是發生的錯誤。這部分代碼和上述相同。咱們能夠用任意一個。 getJSON('promised.json') .then(value => {}, error => {}); // 咱們也能夠鏈式使用promise。 then()方法會返回一個新的Promise對象Q。 getJSON('promised.json') .then(value1 => 123) // 不管第一個then()返回了什麼,它均可以做爲第二個then()的參數。 .then(value2 => {}); // 所以'value2'等於123. // 在鏈式調用中,若是任意一個promise失敗,咱們仍然經過在發生失敗的promise的catch()方法返回一個默認值來繼續執行調用鏈。 getJSON('promised.json') .catch(() => 'default value') // 不管第一個then()返回了什麼,它均可以做爲第二個then()的參數。 .then(value2 => {}); // 所以'value2'等於'default value'. // 咱們也能夠手動拋出異常,它會被傳遞給下一個錯誤處理器。 getJSON('promised.json') .then(value => {throw new Error();}) .then(err => {}); // 有了可鏈式調用的promise,如咱們所知,咱們能夠很輕鬆地作下面這樣的事,擁有嵌套的promise: asyncFunc1() .then(function (value1) { asyncFunc2() .then(function (value2) { // do something else... }); }); // 或者將其扁平化,像下面這樣: asyncFunc1() .then(function (value1) { return asyncFunc2(); }) .then(function (value2) { // do something else... });

著做權歸做者全部。
商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
原文: https://www.w3cplus.com/javascript/lets-learn-ecmascript-6-basics-in-simple-terms.html © w3cplus.com

相關文章
相關標籤/搜索