es六、七、八、9新語法新特性-總結

一、let和const命令

let命令,用來聲明變量。它的用法相似於var,可是所聲明的變量,只在let命令所在的代碼塊內有效javascript

{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1複製代碼

const聲明一個只讀的常量。一旦聲明,常量的值就不能改變。
html

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.複製代碼

二、變量的解構賦值

基本用法java

ES6容許按照必定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構(Destructuring)。
git

本質上,這種寫法屬於「模式匹配」,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值。下面是一些使用嵌套數組進行解構的例子。
github

1)數組的解構賦值正則表達式

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []複製代碼

(2)對象的解構賦值shell

對象的解構與數組有一個重要的不一樣。數組的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值
編程

let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined複製代碼

(3)字符串的解構賦值c#

字符串也能夠解構賦值。這是由於此時,字符串被轉換成了一個相似數組的對象
數組

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"複製代碼

(4)數值和布爾值的解構賦值

解構賦值時,若是等號右邊是數值和布爾值,則會先轉爲對象。

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true複製代碼

(5)函數參數的解構賦值

[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]複製代碼
function add([x, y]){
  return x + y;
}

add([1, 2]); // 3複製代碼

三、字符串的擴展

API:

  • codePointAt():可以正確處理4個字節儲存的字符,返回一個字符的碼點
  • String.fromCodePoint():用於從碼點返回對應字符,可是這個方法不能識別32位的UTF-16字符
  • at():返回字符串給定位置的字符。該方法不能識別碼點大於0xFFFF的字
  • normalize():用來將字符的不一樣表示方法統一爲一樣的形式,這稱爲Unicode正規化。
  • includes():返回布爾值,表示是否找到了參數字符串。
  • startsWith():返回布爾值,表示參數字符串是否在源字符串的頭部
  • endsWith():返回布爾值,表示參數字符串是否在源字符串的尾部。
  • repeat():返回一個新字符串,表示將原字符串重複n次。
  •  padStart()padEnd():若是某個字符串不夠指定長度,會在頭部或尾部補全。padStart用於頭部補全,padEnd用於尾部補全。

(1)字符的Unicode表示法

只要將碼點放入大括號,就能正確解讀該字符。

"\u{20BB7}"
// "𠮷"

"\u{41}\u{42}\u{43}"
// "ABC"

let hello = 123;
hell\u{6F} // 123

'\u{1F680}' === '\uD83D\uDE80'
// true複製代碼

(2)字符串的遍歷器接口

ES6爲字符串添加了遍歷器接口,使得字符串能夠被for...of循環遍歷。

for (let codePoint of 'foo') {
  console.log(codePoint)
}
// "f"
// "o"
// "o"
複製代碼

(3)模板字符串

實例代碼以下,一看便明瞭:

// 普通字符串
`In JavaScript '\n' is a line-feed.`

// 多行字符串
`In JavaScript this is not legal.`

console.log(`string text line 1 string text line 2`);

// 字符串中嵌入變量
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`複製代碼

四、正則的擴展

(1)RegExp構造函數

RegExp構造函數第一個參數是一個正則對象,那麼可使用第二個參數指定修飾符。並且,返回的正則表達式會忽略原有的正則表達式的修飾符,只使用新指定的修飾符。

new RegExp(/abc/ig, 'i').flags
// "i"複製代碼

(2)字符串的正則方法

字符串對象共有4個方法,可使用正則表達式:match()replace()search()split()

ES6將這4個方法,在語言內部所有調用RegExp的實例方法,從而作到全部與正則相關的方法,全都定義在RegExp對象上。

  • String.prototype.match 調用 RegExp.prototype[Symbol.match]
  • String.prototype.replace 調用 RegExp.prototype[Symbol.replace]
  • String.prototype.search 調用 RegExp.prototype[Symbol.search]
  • String.prototype.split 調用 RegExp.prototype[Symbol.split]

(3)u修飾符

  • 點字符
  • Unicode字符表示法
  • 量詞
  • 預約義模式
  • i修飾符

五、ES6 數值的擴展

二進制和八進制表示法

ES6提供了二進制和八進制數值的新的寫法,分別用前綴0b(或0B)和0o(或0O)表示。

API

  • Number.isFinite()
  • Number.isNaN()
  • Number.parseInt()
  • Number.parseFloat()
  • Number.isInteger()
  • Number.EPSILON

六、數組的擴展

Array.from()

用於將兩類對象轉爲真正的數組:相似數組的對象(array-like object)和可遍歷(iterable)的對象(包括ES6新增的數據結構Set和Map)

Array.of()

Array.of方法用於將一組值,轉換爲數組。

七、函數的擴展

ES6容許爲函數的參數設置默認值,即直接寫在參數定義的後面。

function log(x, y = 'World') {
  console.log(x, y);
}

log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello複製代碼

(1)箭頭函數

ES6容許使用「箭頭」(=>)定義函數。

var f = v => v;
// 等於
var f = function(v) {
 return v;
};
複製代碼

(2)擴展運算符

擴展運算符(spread)是三個點(...)。它比如 rest 參數的逆運算,將一個數組轉爲用逗號分隔的參數序列。

console.log(...[1, 2, 3])
// 1 2 3

console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5

[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]複製代碼

八、對象的擴展

(1)屬性和方法的簡潔表示法

ES6容許直接寫入變量和函數,做爲對象的屬性和方法。這樣的書寫更加簡潔。

var foo = 'bar';
var baz = {foo};
baz // {foo: "bar"}

// 等同於
var baz = {foo: foo};複製代碼

(2)方法的簡潔表示

var o = {
  method() {
    return "Hello!";
  }
};

// 等同於

var o = {
  method: function() {
    return "Hello!";
  }
};複製代碼

(3)Object.assign

Object.assign方法用於對象的合併,將源對象(source)的全部可枚舉屬性,複製到目標對象(target)。

var target = { a: 1 };

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

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

Object.assign方法實行的是淺拷貝,而不是深拷貝。也就是說,若是源對象某個屬性的值是對象,那麼目標對象拷貝獲得的是這個對象的引用。

九、Symbol

Symbol值經過Symbol函數生成。這就是說,對象的屬性名如今能夠有兩種類型,一種是原來就有的字符串,另外一種就是新增的Symbol類型。凡是屬性名屬於Symbol類型,就都是獨一無二的,能夠保證不會與其餘屬性名產生衝突。

十、Promise對象

Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最先提出和實現,ES6將其寫進了語言標準,統一了用法,原生提供了Promise對象。

所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。

Promise對象有如下兩個特色。

(1)對象的狀態不受外界影響。Promise對象表明一個異步操做,有三種狀態:Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和Rejected(已失敗)。只有異步操做的結果,能夠決定當前是哪種狀態,任何其餘操做都沒法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是「承諾」,表示其餘手段沒法改變。

(2)一旦狀態改變,就不會再變,任什麼時候候均可以獲得這個結果。Promise對象的狀態改變,只有兩種可能:從Pending變爲Resolved和從Pending變爲Rejected。只要這兩種狀況發生,狀態就凝固了,不會再變了,會一直保持這個結果。若是改變已經發生了,你再對Promise對象添加回調函數,也會當即獲得這個結果。這與事件(Event)徹底不一樣,事件的特色是,若是你錯過了它,再去監聽,是得不到結果的處。

基本用法

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

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

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

  if (/* 異步操做成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});複製代碼

Promise實例生成之後,能夠用then方法分別指定Resolved狀態和Reject狀態的回調函數。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});複製代碼

下面是異步加載圖片的例子。

function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
    var image = new Image();

    image.onload = function() {
      resolve(image);
    };

    image.onerror = function() {
      reject(new Error('Could not load image at ' + url));
    };

    image.src = url;
  });
}複製代碼

十一、set和map數據結構

Set基本用法

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

Set自己是一個構造函數,用來生成Set數據結構

var s = new Set();

[2, 3, 5, 4, 5, 2, 2].map(x => s.add(x));

for (let i of s) {
  console.log(i);
}
// 2 3 5 4複製代碼

Map結構的目的和基本用法

ES6提供了Map數據結構。它相似於對象,也是鍵值對的集合,可是「鍵」的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵。也就是說,Object結構提供了「字符串—值」的對應,Map結構提供了「值—值」的對應,是一種更完善的Hash結構實現。若是你須要「鍵值對」的數據結構,Map比Object更合適。

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複製代碼

十二、Proxy 和 Reflect

Proxy

Proxy 用於修改某些操做的默認行爲,等同於在語言層面作出修改,因此屬於一種「元編程」(meta programming),即對編程語言進行編程。

Proxy 能夠理解成,在目標對象以前架設一層「攔截」,外界對該對象的訪問,都必須先經過這層攔截,所以提供了一種機制,能夠對外界的訪問進行過濾和改寫。Proxy 這個詞的原意是代理,用在這裏表示由它來「代理」某些操做,能夠譯爲「代理器」。

Proxy

Reflect對象與Proxy對象同樣,也是ES6爲了操做對象而提供的新API。Reflect對象的設計目的有這樣幾個。

(1) 將Object對象的一些明顯屬於語言內部的方法(好比Object.defineProperty),放到Reflect對象上。現階段,某些方法同時在ObjectReflect對象上部署,將來的新方法將只部署在Reflect對象上。

(2) 修改某些Object方法的返回結果,讓其變得更合理。好比,Object.defineProperty(obj, name, desc)在沒法定義屬性時,會拋出一個錯誤,而Reflect.defineProperty(obj, name, desc)則會返回false

// 老寫法
try {
  Object.defineProperty(target, property, attributes);
  // success
} catch (e) {
  // failure
}

// 新寫法
if (Reflect.defineProperty(target, property, attributes)) {
  // success
} else {
  // failure
}複製代碼

1三、Iterator和for...of循環

terator(遍歷器)的概念

JavaScript原有的表示「集合」的數據結構,主要是數組(Array)和對象(Object),ES6又添加了Map和Set。這樣就有了四種數據集合,用戶還能夠組合使用它們,定義本身的數據結構,好比數組的成員是Map,Map的成員是對象。這樣就須要一種統一的接口機制,來處理全部不一樣的數據結構。

遍歷器(Iterator)就是這樣一種機制。它是一種接口,爲各類不一樣的數據結構提供統一的訪問機制。任何數據結構只要部署Iterator接口,就能夠完成遍歷操做(即依次處理該數據結構的全部成員)。

Iterator的做用有三個:一是爲各類數據結構,提供一個統一的、簡便的訪問接口;二是使得數據結構的成員可以按某種次序排列;三是ES6創造了一種新的遍歷命令for...of循環,Iterator接口主要供for...of消費。

Iterator的遍歷過程是這樣的。

(1)建立一個指針對象,指向當前數據結構的起始位置。也就是說,遍歷器對象本質上,就是一個指針對象。

(2)第一次調用指針對象的next方法,能夠將指針指向數據結構的第一個成員。

(3)第二次調用指針對象的next方法,指針就指向數據結構的第二個成員。

(4)不斷調用指針對象的next方法,直到它指向數據結構的結束位置。

每一次調用next方法,都會返回數據結構的當前成員的信息。具體來講,就是返回一個包含valuedone兩個屬性的對象。其中,value屬性是當前成員的值,done屬性是一個布爾值,表示遍歷是否結束。

下面是一個模擬next方法返回值的例子。

var it = makeIterator(['a', 'b']);

it.next() // { value: "a", done: false }
it.next() // { value: "b", done: false }
it.next() // { value: undefined, done: true }

function makeIterator(array) {
  var nextIndex = 0;
  return {
    next: function() {
      return nextIndex < array.length ?
        {value: array[nextIndex++], done: false} :
        {value: undefined, done: true};
    }
  };
}複製代碼

for...of循環

ES6 借鑑 C++、Java、C# 和 Python 語言,引入了for...of循環,做爲遍歷全部數據結構的統一的方法。

一個數據結構只要部署了Symbol.iterator屬性,就被視爲具備iterator接口,就能夠用for...of循環遍歷它的成員。也就是說,for...of循環內部調用的是數據結構的Symbol.iterator方法。

for...of循環可使用的範圍包括數組、Set 和 Map 結構、某些相似數組的對象(好比arguments對象、DOM NodeList 對象)、後文的 Generator 對象,以及字符串。

數組原生具有iterator接口(即默認部署了Symbol.iterator屬性),for...of循環本質上就是調用這個接口產生的遍歷器,能夠用下面的代碼證實。

const arr = ['red', 'green', 'blue'];

for(let v of arr) {
  console.log(v); // red green blue
}

const obj = {};
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr);

for(let v of obj) {
  console.log(v); // red green blue
}複製代碼

1四、Generator/yield

Generator函數是ES6提供的一種異步編程解決方案,語法行爲與傳統函數徹底不一樣

Generator函數有多種理解角度。從語法上,首先能夠把它理解成,Generator函數是一個狀態機,封裝了多個內部狀態。

執行Generator函數會返回一個遍歷器對象,也就是說,Generator函數除了狀態機,仍是一個遍歷器對象生成函數。返回的遍歷器對象,能夠依次遍歷Generator函數內部的每個狀態。

形式上,Generator函數是一個普通函數,可是有兩個特徵。一是,function關鍵字與函數名之間有一個星號;二是,函數體內部使用yield語句,定義不一樣的內部狀態(yield語句在英語裏的意思就是「產出」)。

function* helloWorldGenerator() {
  yield 'hello';
  yield 'world';
  return 'ending';
}

var hw = helloWorldGenerator();複製代碼

上面代碼定義了一個Generator函數helloWorldGenerator,它內部有兩個yield語句「hello」和「world」,即該函數有三個狀態:hello,world和return語句(結束執行)。

而後,Generator函數的調用方法與普通函數同樣,也是在函數名後面加上一對圓括號。不一樣的是,調用Generator函數後,該函數並不執行,返回的也不是函數運行結果,而是一個指向內部狀態的指針對象,也就是上一章介紹的遍歷器對象(Iterator Object)。

下一步,必須調用遍歷器對象的next方法,使得指針移向下一個狀態。也就是說,每次調用next方法,內部指針就從函數頭部或上一次停下來的地方開始執行,直到遇到下一個yield語句(或return語句)爲止。換言之,Generator函數是分段執行的,yield語句是暫停執行的標記,而next方法能夠恢復執行。

hw.next()
// { value: 'hello', done: false }

hw.next()
// { value: 'world', done: false }

hw.next()
// { value: 'ending', done: true }

hw.next()
// { value: undefined, done: true }複製代碼

上面代碼一共調用了四次next方法。

第一次調用,Generator函數開始執行,直到遇到第一個yield語句爲止。next方法返回一個對象,它的value屬性就是當前yield語句的值hello,done屬性的值false,表示遍歷尚未結束。

第二次調用,Generator函數從上次yield語句停下的地方,一直執行到下一個yield語句。next方法返回的對象的value屬性就是當前yield語句的值world,done屬性的值false,表示遍歷尚未結束。

第三次調用,Generator函數從上次yield語句停下的地方,一直執行到return語句(若是沒有return語句,就執行到函數結束)。next方法返回的對象的value屬性,就是緊跟在return語句後面的表達式的值(若是沒有return語句,則value屬性的值爲undefined),done屬性的值true,表示遍歷已經結束。

第四次調用,此時Generator函數已經運行完畢,next方法返回對象的value屬性爲undefined,done屬性爲true。之後再調用next方法,返回的都是這個值。

總結一下,調用Generator函數,返回一個遍歷器對象,表明Generator函數的內部指針。之後,每次調用遍歷器對象的next方法,就會返回一個有着valuedone兩個屬性的對象。value屬性表示當前的內部狀態的值,是yield語句後面那個表達式的值;done屬性是一個布爾值,表示是否遍歷結束

yield語句

因爲Generator函數返回的遍歷器對象,只有調用next方法纔會遍歷下一個內部狀態,因此其實提供了一種能夠暫停執行的函數。yield語句就是暫停標誌。

遍歷器對象的next方法的運行邏輯以下。

(1)遇到yield語句,就暫停執行後面的操做,並將緊跟在yield後面的那個表達式的值,做爲返回的對象的value屬性值。

(2)下一次調用next方法時,再繼續往下執行,直到遇到下一個yield語句。

(3)若是沒有再遇到新的yield語句,就一直運行到函數結束,直到return語句爲止,並將return語句後面的表達式的值,做爲返回的對象的value屬性值。

(4)若是該函數沒有return語句,則返回的對象的value屬性值爲undefined

須要注意的是,yield語句後面的表達式,只有當調用next方法、內部指針指向該語句時纔會執行,所以等於爲JavaScript提供了手動的「惰性求值」(Lazy Evaluation)的語法功能。

function* gen() {
  yield  123 + 456;
}複製代碼

上面代碼中,yield後面的表達式123 + 456,不會當即求值,只會在next方法將指針移到這一句時,纔會求值。

yield語句與return語句既有類似之處,也有區別。類似之處在於,都能返回緊跟在語句後面的那個表達式的值。區別在於每次遇到yield,函數暫停執行,下一次再從該位置繼續向後執行,而return語句不具有位置記憶的功能。一個函數裏面,只能執行一次(或者說一個)return語句,可是能夠執行屢次(或者說多個)yield語句。正常函數只能返回一個值,由於只能執行一次return;Generator函數能夠返回一系列的值,由於能夠有任意多個yield。從另外一個角度看,也能夠說Generator生成了一系列的值,這也就是它的名稱的來歷(在英語中,generator這個詞是「生成器」的意思)

1五、async與await

ES7提供了async函數,使得異步操做變得更加方便。async函數是什麼?一句話,async函數就是Generator函數的語法糖。

依次讀取兩個文件。

var fs = require('fs');

var readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) reject(error);
      resolve(data);
    });
  });
};

var gen = function* (){
  var f1 = yield readFile('/etc/fstab');
  var f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};複製代碼

寫成async函數,就是下面這樣

var asyncReadFile = async function (){
  var f1 = await readFile('/etc/fstab');
  var f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
}複製代碼

一比較就會發現,async函數就是將Generator函數的星號(*)替換成async,將yield替換成await,僅此而已。

async函數對 Generator 函數的改進,體如今如下四點

(1)內置執行器。Generator函數的執行必須靠執行器,因此纔有了co模塊,而async函數自帶執行器。也就是說,async函數的執行,與普通函數如出一轍,只要一行。

(2)更好的語義。asyncawait,比起星號和yield,語義更清楚了。async表示函數裏有異步操做,await表示緊跟在後面的表達式須要等待結果。

(3)更廣的適用性。 co模塊約定,yield命令後面只能是Thunk函數或Promise對象,而async函數的await命令後面,能夠是Promise對象和原始類型的值(數值、字符串和布爾值,但這時等同於同步操做)。

(4)返回值是Promise。async函數的返回值是Promise對象,這比Generator函數的返回值是Iterator對象方便多了。你能夠用then方法指定下一步的操做。

進一步說,async函數徹底能夠看做多個異步操做,包裝成的一個Promise對象,而await命令就是內部then命令的語法糖。

1六、Class

對熟悉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複製代碼

1七、模塊化(Module)

ES5不支持原生的模塊化,在ES6中模塊做爲重要的組成部分被添加進來。模塊的功能主要由 export 和 import 組成。每個模塊都有本身單獨的做用域,模塊之間的相互調用關係是經過 export 來規定模塊對外暴露的接口,經過import來引用其它模塊提供的接口。同時還爲模塊創造了命名空間,防止函數的命名衝突。

導出(export)

ES6容許在一個模塊中使用export來導出多個變量或函數。

導出變量/常量

//test.js
export var name = 'Rainbow'
複製代碼

ES6將一個文件視爲一個模塊,上面的模塊經過 export 向外輸出了一個變量。一個模塊也能夠同時往外面輸出多個變量。

//test.js
 var name = 'Rainbow';
 var age = '24';
 export {name, age};
複製代碼

導出函數

// myModule.js
export function myModule(someArg) {
  return someArg;
} 
複製代碼

導入(import)

定義好模塊的輸出之後就能夠在另一個模塊經過import引用。

import {myModule} from 'myModule';// main.js
import {name,age} from 'test';// test.js
複製代碼

1八、修飾器(Decorator)

修飾器(Decorator)是一個函數,用來修改類的行爲。這是ES7的一個提案,目前Babel轉碼器已經支持。

修飾器對類的行爲的改變,是代碼編譯時發生的,而不是在運行時。這意味着,修飾器能在編譯階段運行代碼。

類的修飾

function testable(target) {
  target.isTestable = true;
}

@testable
class MyTestableClass {}

console.log(MyTestableClass.isTestable) // true複製代碼

上面代碼中,@testable就是一個修飾器。它修改了MyTestableClass這個類的行爲,爲它加上了靜態屬性isTestable

基本上,修飾器的行爲就是下面這樣。

@decorator
class A {}

// 等同於

class A {}
A = decorator(A) || A;複製代碼

方法的修飾

class Person {
  @readonly
  name() { return `${this.first} ${this.last}` }
}複製代碼

參考

ECMAScript® 2016 語言標準

ECMAScript® 2017

相關文章
相關標籤/搜索