ES6 新特性


ES6, 全稱 ECMAScript 6.0 ,2015.06 發版。ES6 主要是為了解決 ES5 的先天不足,比如 JavaScript 里並沒有類的概念,但是目前瀏覽器的 JavaScript 是 ES5 版本,大多數高版本的瀏覽器也支持 ES6,不過只實現了 ES6 的部分特性和功能。

平時項目開發也用得很久,現在整體復習下。

1、let、const、block作用域

let 允許創建塊級作用域(最靠近的一個花括號內有效),不具備變量提升,不允許重復聲明:

// 塊級作用域
{
  let a = 1
  console.log(a)  // 1
}
console.log(a) // Uncaught ReferenceError: a is not defined

// 變量不提升
{
  console.log(a) // Uncaught ReferenceError: Cannot access 'a' before initialization
  let a = 1
}

// 不能重復聲明
{
  let a = 1
  let a = 2 // Uncaught SyntaxError: Identifier 'a' has already been declared
}

const 允許創建塊級作用域(最靠近的一個花括號內有效)、變量聲明不提升、const 在聲明時必須被賦值、聲明時大寫變量(默認規則):

// 塊級作用域
{
  const A = 1
  console.log(A)
}
console.log(A) // Uncaught ReferenceError: A is not defined

// 變量不提升
{
  console.log(A) // Uncaught ReferenceError: Cannot access 'A' before initialization
  const A = 1
}

// 聲明時必須賦值
{
  const A // Uncaught SyntaxError: Missing initializer in const declaration
}

2、箭頭函數

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

// ES5寫法
var getPrice = function() {
  return 4.55;
};
 
// ES6箭頭函數寫法,不需要return語句
var getPrice = () => 4.55;

箭頭函數不具備this變量指向改變:

// ES5
function Person() {
  this.age = 0;
 
  setInterval(function growUp() {
    // 在非嚴格模式下,growUp() 函數的 this 指向 window 對象
    this.age++;
  }, 1000);
}
var person = new Person();

// ES6
function Person(){
  this.age = 0;
 
  setInterval(() => {
    // |this| 指向 person 對象
    this.age++;
  }, 1000);
}
 
var person = new Person();

3、函數參數默認值

ES6 中允許你對函數參數設置默認值:

// ES5
var getFinalPrice = function (price, tax) {
  tax = tax || 0.7
  return price + price * tax;
}

// ES6
var getFinalPrice = function (price, tax = 0.7) {
  return price + price * tax;
}

4、Spread/Rest操作符

Spread / Rest 操作符指的是運算符...:

// Spread,可以簡單理解為分散
function foo(x,y,z) {
  console.log(x,y,z);
}
 
let arr = [1,2,3];
foo(...arr); // 1 2 3

// Rest,可以簡單理解為合並
function foo(...args) {
  console.log(args);
}
foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]

5、對象詞法擴展

ES6 允許聲明在對象字面量時使用簡寫語法,來初始化屬性變量和函數的定義方法,並且允許在對象屬性中進行計算操作:

function getCar(make, value) {
  return {
    // 簡寫變量
    make,  // 等同於 make: make
    value, // 等同於 value: value

    // 屬性可以使用表達式計算值
    ['make' + make]: true,

    // 忽略 `function` 關鍵詞簡寫對象函數
    depreciate() {
      this.value -= 2500;
    },
    // ES5寫法
    depreciateBak: function () {
      console.log(this['make' + this.make])
    }
  }
};

6、二進制和八進制字面量

ES6 支持二進制和八進制的字面量,通過在數字前面添加 0o 或者0O 即可將其轉換為八進制值:

let oValue = 0o10;
console.log(oValue); // 8
 
let bValue = 0b10; // 二進制使用 `0b` 或者 `0B`
console.log(bValue); // 2

7、對象和數組的結構

解構可以避免在對象賦值時產生中間變量:

let obj = { a: 1, b: 2, c: 3 }
let { a: a1, b: b1, c: c1 } = obj
console.log(a1, b1, c1) // 1 2 3
// let { a, b, c } = obj // 等同上面
// console.log(a, b, c) // 1 2 3

let arr = [1, 2, 3]
let [d, e, f] = arr
console.log(d, e, f) // 1 2 3

8、對象超類

ES6 允許在對象中使用 super 方法:

var parent = {
  foo() {
    console.log("Hello from the Parent");
  }
}
var child = {
  foo() {
    super.foo();
    console.log("Hello from the Child");
  }
}
Object.setPrototypeOf(child, parent); // child.__proto__ = parent
child.foo(); // Hello from the Parent
             // Hello from the Child

9、模板語法和分隔符

一種十分簡潔的方法組裝一堆字符串和變量。

let user = 'Barret';
// ``作為分隔符,${ ... }用來渲染一個變量
console.log(`Hi ${user}!`); // Hi Barret!

10、for...of VS for...in

for...of 用於遍歷一個迭代器,如數組:

let nicknames = ['di', 'boo', 'punkeye'];
nicknames.size = 3;
for (let nickname of nicknames) {
  console.log(nickname);
}
// 結果: di, boo, punkeye

for...in 用來遍歷對象中的屬性(只能訪問可枚舉的):

let nicknames = ['di', 'boo', 'punkeye'];
nicknames.size = 3;
for (let nickname in nicknames) {
  console.log(nickname);
}
// 0, 1, 2, size

11、Map VS WeakMap

ES6 中兩種新的數據結構集:Map 和 WeakMap。事實上每個對象都可以看作是一個 Map。

一個對象由多個 key-val 對構成,在 Map 中,任何類型都可以作為對象的 key,如:

var myMap = new Map();
 
var keyString = "a string",
    keyObj = {},
    keyFunc = function () {};
 
// 設置值
myMap.set(keyString, "value 與 'a string' 關聯");
myMap.set(keyObj, "value 與 keyObj 關聯");
myMap.set(keyFunc, "value 與 keyFunc 關聯");
 
myMap.size; // 3
 
// 獲取值
myMap.get(keyString);    // "value 與 'a string' 關聯"
myMap.get(keyObj);       // "value 與 keyObj 關聯"
myMap.get(keyFunc);      // "value 與 keyFunc 關聯"

WeakMap 就是一個 Map,只不過它的所有 key 都是弱引用,意思就是 WeakMap 中的東西垃圾回收時不考慮,使用它不用擔心內存泄漏問題。

另一個需要注意的點是,WeakMap 的所有 key 必須是對象。它只有四個方法 delete(key),has(key),get(key) 和set(key, val):

let w = new WeakMap();
w.set('a', 'b'); 
// Uncaught TypeError: Invalid value used as weak map key
 
var o1 = {},
    o2 = function(){},
    o3 = window;
 
w.set(o1, 37);
w.set(o2, "azerty");
w.set(o3, undefined);
 
w.get(o3); // undefined, because that is the set value
 
w.has(o1); // true
w.delete(o1);
w.has(o1); // false

12、Set VS WeakSet

Set 對象是一組不重復的值,重復的值將被忽略,值類型可以是原始類型和引用類型:

let mySet = new Set([1, 1, 2, 2, 3, 3]);
mySet.size; // 3
mySet.has(1); // true
mySet.add('strings');
mySet.add({ a: 1, b:2 });

基於Set對象的值不重復,即有一種非常方便的數組去重方法:

// 得到Set格式的值 
let mySet = new Set([1, 1, 2, 2, 3, 3]);
// mySet => Set(3) {1, 2, 3}
// Object.prototype.toString.call(mySet) // [object Set]

let toArray = Array.from(mySet) // [1, 2, 3]
Object.prototype.toString.call(toArray) // [object Array]

可以通過 forEach 和 for...of 來遍歷 Set 對象:

mySet.forEach((item) => {
  console.log(item);
    // 1
    // 2
    // 3
    // 'strings'
    // Object { a: 1, b: 2 }
});
 
for (let value of mySet) {
  console.log(value);
    // 1
    // 2
    // 3
    // 'strings'
    // Object { a: 1, b: 2 }
}

Set 同樣有 delete() 和 clear() 方法。

類似於 WeakMap,WeakSet 對象可以讓你在一個集合中保存對象的弱引用,在 WeakSet 中的對象只允許出現一次:

var ws = new WeakSet();
var obj = {};
var foo = {};
 
ws.add(window);
ws.add(obj);
 
ws.has(window); // true
ws.has(foo);    // false, foo 沒有添加成功
 
ws.delete(window); // 從結合中刪除 window 對象
ws.has(window);    // false, window 對象已經被刪除

13、類

ES6 中有 class 語法。值得注意是,這里的 class 不是新的對象繼承模型,它只是原型鏈的語法糖表現形式。

函數中使用 static 關鍵詞定義構造函數的的方法和屬性:

class Task {
  constructor() {
    console.log("task instantiated!");
  }
  showId() {
    console.log(23);
  }
  static loadAll() {
    console.log("Loading all tasks..");
  }
}
 
console.log(typeof Task); // function
let task = new Task(); // "task instantiated!"
task.showId(); // 23
Task.loadAll(); // "Loading all tasks.."

類中的繼承和超集:

class Car {
  constructor() {
    console.log("Creating a new car");
  }
  call(val) {
    console.log('parent --->', val)
  }
}

class Porsche extends Car {
  constructor() {
    super();
    console.log("Creating Porsche");
    super.call('inner')
  }
  call2(val) {
    super.call(val)
  }
}

let c = new Porsche();
c.call2('outer')

// Creating a new car
// Creating Porsche
// parent ---> inner
// parent ---> outer

extends 允許一個子類繼承父類,需要注意的是,子類的constructor 函數中需要執行 super() 函數。

當然,你也可以在子類方法中調用父類的方法,如super.parentMethodName()。

有幾點值得注意的是:

  • 類的聲明不會提升(hoisting),如果你要使用某個 Class,那你必須在使用之前定義它,否則會拋出一個 ReferenceError 的錯誤
  • 在類中定義函數不需要使用 function 關鍵詞

14、Symbol

Symbol 是一種新的數據類型,它的值是唯一的,不可變的。ES6 中提出 symbol 的目的是為了生成一個唯一的標識符,不過你訪問不到這個標識符:

var sym = Symbol( "some optional description" );
console.log(typeof sym); // symbol

注意,這里 Symbol 前面不能使用 new 操作符。

如果它被用作一個對象的屬性,那么這個屬性會是不可枚舉的:

// 因為Symbol的值是唯一的
Symbol(1) == Symbol(1) // false

let ran = Symbol("random")
var o = {
  val: 10,
  [ran]: "I'm a symbol",
};

console.log(Object.getOwnPropertyNames(o)) // val
console.log(o[ran]) // "I'm a symbol"

15、迭代器(Iterators)

迭代器允許每次訪問數據集合的一個元素,當指針指向數據集合最后一個元素是,迭代器便會退出。它提供了 next() 函數來遍歷一個序列,這個方法返回一個包含 done 和 value 屬性的對象。

ES6 中可以通過 Symbol.iterator 給對象設置默認的遍歷器,無論什么時候對象需要被遍歷,執行它的 @@iterator 方法便可以返回一個用於獲取值的迭代器。

數組默認就是一個迭代器:

var arr = [11,12,13];
var itr = arr[Symbol.iterator]();
 
itr.next(); // { value: 11, done: false }
itr.next(); // { value: 12, done: false }
itr.next(); // { value: 13, done: false }
 
itr.next(); // { value: undefined, done: true }

可以通過 [Symbol.iterator]() 自定義一個對象的迭代器。

16、Generators

Generator 函數是 ES6 的新特性,它允許一個函數返回的可遍歷對象生成多個值(返回的值為一個迭代器對象)。

在使用中你會看到 * 語法和一個新的關鍵詞 yield:

function *infiniteNumbers() {
  var n = 1;
  while (true){
    yield n++;
  }
}
 
var numbers = infiniteNumbers(); // returns an iterable object
 
numbers.next(); // { value: 1, done: false }
numbers.next(); // { value: 2, done: false }
numbers.next(); // { value: 3, done: false }

每次執行 yield 時,返回的值變為迭代器的下一個值。

17、Promise

ES6 對 Promise 有了原生的支持,一個 Promise 是一個等待被異步執行的對象,當它執行完成后,其狀態會變成 resolved 或者rejected。

var p = new Promise(function(resolve, reject) {  
  if (/* condition */) {
    // fulfilled successfully
    resolve(/* value */);  
  } else {
    // error, rejected
    reject(/* reason */);  
  }
});

p.then((val) => console.log("Promise Resolved", val),
       (err) => console.log("Promise Rejected", err));

18、Proxy 與 Reflect

Proxy 可以對目標對象的讀取、函數調用等操作進行攔截,然后進行操作處理。它不直接操作對象,而是像代理模式,通過對象的代理對象進行操作,在進行這些操作時,可以添加一些需要的額外操作。

Reflect 可以用於獲取目標對象的行為,它與 Object 類似,但是更易讀,為操作對象提供了一種更優雅的方式。它的方法與 Proxy 是對應的。

Proxy詳情,點這里

Reflect詳情,點這里。

19、字符串

ES6 對字符串操作方法的擴展。

  • includes():返回布爾值,判斷是否找到參數字符串。
  • startsWith():返回布爾值,判斷參數字符串是否在原字符串的頭部。
  • endsWith():返回布爾值,判斷參數字符串是否在原字符串的尾部。
  • repeat():返回新的字符串,表示將字符串重復指定次數返回。
  • padStart:返回新的字符串,表示用參數字符串從頭部(左側)補全原字符串。
  • padEnd:返回新的字符串,表示用參數字符串從尾部(右側)補全原字符串。

20、模塊

在 ES6 前, 實現模塊化使用的是 RequireJS 或者 seaJS(分別是基於 AMD 規范的模塊化庫,  和基於 CMD 規范的模塊化庫)。

ES6 引入了模塊化,其設計思想是在編譯時就能確定模塊的依賴關系,以及輸入和輸出的變量。

ES6 的模塊化分為導出(export) @與導入(import)兩個模塊。

export 與 import:

  • 導出的函數聲明與類聲明必須要有名稱(export default 命令另外考慮)。 
  • 不僅能導出聲明還能導出引用(例如函數)。
  • export 命令可以出現在模塊的任何位置,但必需處於模塊頂層。
  • import 命令會提升到整個模塊的頭部,首先執行。

as的用法:

export 命令導出的接口名稱,須和模塊內部的變量有一一對應關系。導入的變量名,須和導出的接口名稱相同,即順序可以不一致。使用 as 重新定義導出的接口名稱,隱藏模塊內部的變量

export default 命令:

  • 在一個文件或模塊中,export、import 可以有多個,export default 僅有一個。
  • export default 中的 default 是對應的導出接口變量。
  • 通過 export 方式導出,在導入時要加{ },export default 則不需要。
  • export default 向外暴露的成員,可以使用任意變量來接收。

21、async / await

async 是 ES7 才有的與異步操作有關的關鍵字,和 Promise , Generator 有很大關聯的。

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

async 函數中可能會有 await 表達式,async 函數執行時,如果遇到 await 就會先暫停執行 ,等到觸發的異步操作完成后,恢復 async 函數的執行並返回解析值。

await 關鍵字只在 async 函數內有效,否則會報錯。await 返回 Promise 對象的處理結果,如果等待的不是 Promise 對象,則返回該值本身。如果一個 Promise 被傳遞給一個 await 操作符,await 將等待 Promise 正常處理完成並返回其處理結果。

await針對所跟不同表達式的處理方式:

  • Promise 對象:await 會暫停執行,等待 Promise 對象 resolve,然后恢復 async 函數的執行並返回解析值。
  • 非 Promise 對象:直接返回對應的值。

 

原址菜鳥:https://www.runoob.com/w3cnote/es6-concise-tutorial.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM