ES6新特性

變量

(一) const 與 let以及var

1. 三者之間區別

  • 1.變量提高
  1. var聲明 不管聲明在何處,都會被視爲聲明在函數的最頂部
  2. let和const聲明不會提高
  • 2.做用域
  1. var是函數做用域, 在函數內部做用, 可是{}裏是同樣會提高的
  2. let和const是塊級做用域, 在{}裏就造成了一個做用域
  • 3.重複聲明
  1. var 能夠重複定義
  2. let和const不能夠重複定義,不然報錯
  • 4.const常量不可修改
  1. const 聲明的變量都會被認爲是常量,意思就是它的值被設置完成後就不能再修改了;
  • 5. 若是const的是一個對象,對象所包含的值是能夠被修改的。抽象一點兒說,就是對象所指向的地址沒有變就行:
const student = { name: 'cc' }
student.name = 'yy';// 不報錯
student  = { name: 'yy' };// 報錯
複製代碼

2. 暫時性死區

var tmp = 123;
if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}
複製代碼
  • 上面代碼中,存在全局變量tmp,可是塊級做用域內let又聲明瞭一個局部變量tmp,致使後者綁定這個塊級做用域,因此在let聲明變量前,對tmp賦值會報錯。

有幾個點須要注意:前端

# let 關鍵詞聲明的變量不具有變量提高(hoisting)特性
# let 和 const 聲明只在最靠近的一個塊中(花括號內)有效
# 當使用常量 const 聲明時,請使用大寫變量,如:CAPITAL_CASING
# const 在聲明時必須被賦值
複製代碼

3. 建議

在平常開發中,個人建議是全面擁抱let/const,通常的變量聲明使用let關鍵字,而當聲明一些配置項(相似接口地址,npm依賴包,分頁器默認頁數等一些一旦聲明後就不會改變的變量)的時候可使用const,來顯式的告訴項目其餘開發者,這個變量是不能改變的(const聲明的常量建議使用全大寫字母標識,單詞間用下劃線),同時也建議瞭解var關鍵字的缺陷(變量提高,污染全局變量等),這樣才能更好的使用新語法vue

函數

(一) 箭頭函數(Arrow Functions)

  • ES6 中,箭頭函數就是函數的一種簡寫形式,使用括號包裹參數,跟隨一個 =>,緊接着是函數體;

1. 箭頭函數對於使用function關鍵字建立的函數有如下區別:

  1. 箭頭函數沒有arguments(建議使用更好的語法,剩餘運算符替代)
  2. 箭頭函數沒有prototype屬性,不能用做構造函數(不能用new關鍵字調用)
  3. 箭頭函數沒有本身this,它的this是詞法的,引用的是上下文的this,即在你寫這行代碼的時候就箭頭函數的this就已經和外層執行上下文的this綁定了(這裏我的認爲並不表明徹底是靜態的,由於外層的上下文還是動態的可使用call,apply,bind修改,這裏只是說明了箭頭函數的this始終等於它上層上下文中的this)

2. 箭頭函數最直觀的三個特色

# 不須要 function 關鍵字來建立函數
# 省略 return 關鍵字
# 繼承當前上下文的 this 關鍵字
複製代碼
  • 細節:當你的函數有且僅有一個參數的時候,是能夠省略掉括號的。當你函數返回有且僅有一個表達式的時候能夠省略{} 和 return;

3. 規則

  1. 使用了塊語句的箭頭函數不會自動返回值,你須要使用return語句將所需值返回。
  2. 不能夠看成構造函數,即,不可使用new 關鍵字來實例化對象,不然會拋出一個錯誤。
  3. 不可使用arguments對象,更不能經過arguments對象訪問傳入參數,該對象在函數體內不存在。若是要用,能夠用 rest 參數代替。
  4. 不可使用yield命令,所以箭頭函數不能用做 Generator 函數.
  5. 返回的就是一個對象, 須要在外面加一個括號 var getTempItem = id = > ({id: id,});

(二) 函數的參數默認值

// ES6以前,當未傳入參數時,text = 'default'function printText(text) {
    text = text || 'default';
    console.log(text);
}
// ES6;
function printText(text = 'default') {
    console.log(text);
}
printText('hello'); // hello
printText();// default
複製代碼

(三) Promise(經常使用)

Promise做爲ES6中推出的新的概念,改變了JS的異步編程,現代前端大部分的異步請求都是使用Promise實現,fetch這個web api也是基於Promise的,這裏不得簡述一下以前統治JS異步編程的回調函數,回調函數有什麼缺點,Promise又是怎麼改善這些缺點react

回調函數缺點

  1. 多重嵌套,致使回調地獄
  2. 代碼跳躍,並不是人類習慣的思惟模式
  3. 信任問題,你不能把你的回調徹底寄託與第三方庫,由於你不知道第三方庫到底會怎麼執行回調(屢次執行)
  4. 第三方庫可能沒有提供錯誤處理
  5. 不清楚回調是否都是異步調用的(能夠同步調用ajax,在收到響應前會阻塞整個線程,會陷入假死狀態,很是不推薦)

Promise

針對回調函數這麼多缺點,ES6中引入了一個新的概念Promise,Promise是一個構造函數,經過new關鍵字建立一個Promise的實例,來看看Promise是怎麼解決回調函數的這些問題es6

  1. 不清楚回調是否都是異步調用的(能夠同步調用ajax,在收到響應前會阻塞整個線程,會陷入假死狀態,很是不推薦)
  • Promise在設計的時候保證全部響應的處理回調都是異步調用的,不會阻塞代碼的執行,Promise將then方法的回調放入一個叫微任務的隊列中(MicroTask),確保這些回調任務在同步任務執行完之後再執行,這部分一樣也是事件循環的知識點,有興趣的朋友能夠深刻研究一下

建議

  • 在平常開發中,建議全面擁抱新的Promise語法,其實如今的異步編程基本也都使用的是Promise
  • 建議使用ES7的async/await進一步的優化Promise的寫法,async函數始終返回一個Promise,await能夠實現一個"等待"的功能,async/await被成爲異步編程的終極解決方案,即用同步的形式書寫異步代碼,而且可以更優雅的實現異步代碼順序執行以及在發生異步的錯誤時提供更精準的錯誤信息

字符串

(一) 字符串模板

  • 須要拼接字符串的時候儘可能改爲使用模板字符串:
// bad
const foo = 'this is a' + example;

// good
const foo = `this is a ${example}`;
複製代碼
  • 而對ES6來講
    • 基本的字符串格式化。將表達式嵌入字符串中進行拼接。用${}來界定;
    • ES6反引號(``)直接搞定;

數組

for ... of循環

  • for ... of是做爲ES6新增的遍歷方式,容許遍歷一個含有iterator接口的數據結構而且返回各項的值,和ES3中的for ... in的區別以下
  1. for ... of只能用在可迭代對象上,獲取的是迭代器返回的value值, for ... in 能夠獲取全部對象的鍵名
  2. for ... in會遍歷對象的整個原型鏈,性能很是差不推薦使用, 而for ... of只遍歷當前對象不會遍歷它的原型鏈
  3. 對於數組的遍歷,for ... in會返回數組中全部可枚舉的屬性(包括原型鏈上可枚舉的屬性), for ... of只返回數組的下標對應的屬性值
  • for ... of循環的原理其實也是利用了可迭代對象內部部署的iterator接口,若是將for ... of循環分解成最原始的for循環,內部實現的機制能夠這麼理解

  • 能夠看到只要知足第二個條件(iterator.next()存在且res.done爲true)就能夠一直循環下去,而且每次把迭代器的next方法生成的對象賦值給res,而後將res的value屬性賦值給for ... of第一個條件中聲明的變量便可,res的done屬性控制是否繼續遍歷下去

3. for... of循環同時支持break,continue,return(在函數中調用的話)而且能夠和對象解構賦值一塊兒使用

  • arr數組每次使用for ... of循環都返回一對象({a:1},{a:2},{a:3}),而後會通過對象解構,尋找屬性爲a的值,賦值給obj.a,因此在每輪循環的時候obj.a會分別賦值爲1,2,3

對象

(一) 對象屬性/方法簡寫(經常使用)

1. es6容許當對象的屬性和值相同時,省略屬性名

  • 須要注意的是**
    • 省略的是屬性名而不是值
    • 值必須是一個變量

2. 對象屬性簡寫常常與解構賦值一塊兒使用

  • 結合上文的解構賦值,這裏的代碼會實際上是聲明瞭x,y,z變量,由於bar函數會返回一個對象,這個對象有x,y,z這3個屬性,解構賦值會尋找等號右邊表達式的x,y,z屬性,找到後賦值給聲明的x,y,z變量

3. 方法簡寫

  • es6容許當一個對象的屬性的值是一個函數(便是一個方法),可使用簡寫的形式

Module模塊化(經常使用)

在ES6 Module出現以前,模塊化一直是前端開發者討論的重點,面對日益增加的需求和代碼,須要一種方案來將臃腫的代碼拆分紅一個個小模塊,從而推出了AMD,CMD和CommonJs這3種模塊化方案,前者用在瀏覽器端,後面2種用在服務端,直到ES6 Module出現web

  • ES6 Module默認目前尚未被瀏覽器支持,須要使用babel,在平常寫demo的時候常常會顯示這個錯誤

Module特色

  1. ES6 Module是靜態的,也就是說它是在編譯階段運行,和var以及function同樣具備提高效果(這個特色使得它支持tree shaking)
  2. 自動採用嚴格模式(頂層的this返回undefined)
  3. ES6 Module支持使用export {<變量>}導出具名的接口,或者export default導出匿名的接口

心得:ES6不只支持變量的導出,也支持常量的導出。 export const sqrt = Math.sqrt;//導出常量ajax

心得:一條import 語句能夠同時導入默認函數和其它變量。import default Method, { otherMethod } from 'xxx.js';vuex

module.js導出

import導入

  • 這二者的區別是,export {<變量>}導出的是一個變量的引用,export default導出的是一個值
  • 什麼意思呢,就是說在a.js中使用import導入這2個變量的後,在module.js中由於某些緣由x變量被改變了,那麼會馬上反映到a.js,而module.js中的y變量改變後,a.js中的y仍是原來的值

ES6 Module和CommonJs的一些區別

  1. CommonJs輸出的是一個值的拷貝,ES6 Module經過export {<變量>}輸出的是一個變量的引用,export default輸出的是一個值
  2. CommonJs運行在服務器上,被設計爲運行時加載,即代碼執行到那一行纔回去加載模塊,而ES6 Module是靜態的輸出一個接口,發生在編譯的階段
  3. CommonJs在第一次加載的時候運行一次而且會生成一個緩存,以後加載返回的都是緩存中的內容

import()動態加載

  • 關於ES6 Module靜態編譯的特色,致使了沒法動態加載,可是老是會有一些須要動態加載模塊的需求,因此如今有一個提案,使用把import做爲一個函數能夠實現動態加載模塊,它返回一個Promise,Promise被resolve時的值爲輸出的模塊

  • Vue中路由的懶加載的ES6寫法就是使用了這個技術,使得在路由切換的時候可以動態的加載組件渲染視圖

解構賦值

理解

解構賦值能夠直接使用對象的某個屬性,而不須要經過屬性訪問的形式使用,對象解構原理我的認爲是經過尋找相同的屬性名,而後原對象的這個屬性名的值賦值給新對象對應的屬性, 鍵找鍵,找到了就賦值了npm

  • 解構數組
var arr = [1, 2, 3, 4];
let [a, b, c, d] = arr;
console.log(a); // 1
console.log(b); // 2
複製代碼
  • 解構對象
var luke = { occupation: 'jedi', father: 'anakin' };
let {occupation, father} = luke;
console.log(occupation); // jedi
console.log(father); // anakin
複製代碼
  • vuex使用對象解構

建議

一樣建議使用,由於解構賦值語意化更強,對於做爲對象的函數參數來講,能夠減小形參的聲明,直接使用對象的屬性(若是嵌套層數過多我我的認爲不適合用對象解構,不太優雅)編程

剩餘運算符rest/擴展運算符(經常使用)

剩餘/擴展運算符一樣也是ES6一個很是重要的語法,使用3個點(...),後面跟着一個含有iterator接口的數據結構c#

擴展運算符

  • 以數組爲例,使用擴展運算符使得能夠"展開"這個數組,能夠這麼理解,數組是存放元素集合的一個容器,而使用擴展運算符能夠將這個容器拆開,這樣就只剩下元素集合,你能夠把這些元素集合放到另一個數組裏面, 代替ES3中數組原型的concat方法

剩餘運算符

剩餘運算符最重要的一個特色就是替代了之前的arguments

rest只是形參, 能夠隨意取名

  • 訪問函數的arguments對象是一個很昂貴的操做,之前的arguments.callee,arguments.caller都被廢止了,建議在支持ES6語法的環境下不要在使用arguments對象,使用剩餘運算符替代(箭頭函數沒有arguments,必須使用剩餘運算符才能訪問參數集合)

  • 剩餘運算符能夠和數組的解構賦值一塊兒使用,可是必須放在最後一個,由於剩餘運算符的原理實際上是利用了數組的迭代器,它會消耗3個點後面的數組的全部迭代器,讀取全部迭代器生成對象的value屬性,剩運算符後不能在有解構賦值,由於剩餘運算符已經消耗了全部迭代器,而數組的解構賦值也是消耗迭代器,可是這個時候已經沒有迭代器了,因此會報錯

  • 這裏first會消耗右邊數組的一個迭代器,...arr會消耗剩餘全部的迭代器,而第二個例子...arr直接消耗了全部迭代器,致使last沒有迭代器可供消耗了,因此會報錯,由於這是毫無心義的操做

區別

剩餘運算符和擴展運算符的區別就是,剩餘運算符會收集這些集合,放到右邊的數組中,擴展運算符是將右邊的數組拆分紅元素的集合,它們是相反的

在對象中使用擴展運算符

  • 這個是ES9的語法,ES9中支持在對象中使用擴展運算符,以前說過數組的擴展運算符原理是消耗全部迭代器,但對象中並無迭代器,我我的認爲多是實現原理不一樣,可是仍能夠理解爲將鍵值對從對象中拆開,它能夠放到另一個普通對象中

  • 其實它和另一個ES6新增的API類似,即Object.assign,它們均可以合併對象,可是仍是有一些不一樣Object.assign會觸發目標對象的setter函數,而對象擴展運算符不會

建議

  • 使用擴展運算符能夠快速的將類數組轉爲一個真正的數組
  • 合併多個數組

函數柯理化

類(class) (ES6)

對熟悉Java,object-c,c#等純面嚮對象語言的開發者來講,都會對class有一種特殊的情懷。ES6 引入了class(類),讓JavaScript的面向對象編程變得更加簡單和易於理解。

class Animal {
    // 構造函數,實例化的時候將會被調用,若是不指定,那麼會有一個不帶參數的默認構造函數.
    constructor(name,color) {
      this.name = name;
      this.color = color;
    }
    // toString 是原型對象上的屬性
    toString() {
      console.log('name:' + this.name + ',color:' + this.color);

    }
  }

 var animal = new Animal('dog','white');//實例化Animal
 animal.toString();

 console.log(animal.hasOwnProperty('name')); //true
 console.log(animal.hasOwnProperty('toString')); // false
 console.log(animal.__proto__.hasOwnProperty('toString')); // true

 class Cat extends Animal {
  constructor(action) {
    // 子類必需要在constructor中指定super 函數,不然在新建實例的時候會報錯.
    // 若是沒有置頂consructor,默認帶super函數的constructor將會被添加、
    super('cat','white');
    this.action = action;
  }
  toString() {
    console.log(super.toString());
  }
 }

 var cat = new Cat('catch')
 cat.toString();

 // 實例cat 是 Cat 和 Animal 的實例,和Es5徹底一致。
 console.log(cat instanceof Cat); // true
 console.log(cat instanceof Animal); // true
複製代碼

includes

includes() 函數用來判斷一個數組是否包含一個指定的值,若是包含則返回 true,不然返回false。

includes 函數與 indexOf 函數很類似,下面兩個表達式是等價的:

arr.includes(x)
arr.indexOf(x) >= 0
複製代碼

接下來咱們來判斷數字中是否包含某個元素:

在ES7以前的作法

使用indexOf()驗證數組中是否存在某個元素,這時須要根據返回值是否爲-1來判斷:

let arr = ['react', 'angular', 'vue'];

if (arr.indexOf('react') !== -1)
{
    console.log('react存在');
}
複製代碼

使用ES7的includes()

使用includes()驗證數組中是否存在某個元素,這樣更加直觀簡單:

let arr = ['react', 'angular', 'vue'];

if (arr.includes('react'))
{
    console.log('react存在');
}
複製代碼

指數操做符

在ES7中引入了指數運算符****具備與Math.pow(..)等效的計算結果。

不使用指數操做符

使用自定義的遞歸函數calculateExponent或者Math.pow()進行指數運算:

function calculateExponent(base, exponent)
{
    if (exponent === 1)
    {
        return base;
    }
    else
    {
        return base * calculateExponent(base, exponent - 1);
    }
}

console.log(calculateExponent(2, 10)); // 輸出1024
console.log(Math.pow(2, 10)); // 輸出1024
複製代碼
複製代碼

使用指數操做符

使用指數運算符**,就像+、-等操做符同樣:

console.log(2**10);// 輸出1024
複製代碼

1

相關文章
相關標籤/搜索