ECMAScript 6學習筆記

1.環境支持
首先,必須在網頁頭部加載Traceur庫文件
  1. <!-- 加載Traceur編譯器 -->
  2. <scriptsrc="http://google.github.io/traceur-compiler/bin/traceur.js" type="text/javascript"></script>
  3. <!-- 將Traceur編譯器用於網頁 -->
  4. <scriptsrc="http://google.github.io/traceur-compiler/src/bootstrap.js" type="text/javascript"></script>
  5. <!-- 打開實驗選項,否則有些特性可能編譯不成功 -->
  6. <script>
  7. traceur.options.experimental =true;
  8. </script>
  9. <scripttype="module">
  10. classCalc{
  11. constructor(){
  12. console.log('Calc constructor');
  13. }
  14. add(a, b){
  15. return a + b;
  16. }
  17. }
  18. var c =newCalc();
  19. console.log(c.add(4,5));
  20. </script>

注意,script標籤的type屬性的值是module(或者traceur),而不是text/javascript。這是Traceur編譯器識別ES6代碼的標識,編譯器會自動將所有type=module的代碼編譯爲ES5,然後再交給瀏覽器執行。

2.新增關鍵字

(1)let是ES6中新增關鍵字。它的作用類似於var,用來聲明變量,但是所聲明的變量,只在let命令所在的代碼塊內有效。

(2)const 聲明的是常量,一旦聲明,值將是不可變的。const 的特點:

  • 具有塊級作用域
  • 不能變量提升(必須先聲明後使用)
  • 不可重複聲明
  • const 指令指向變量所在的地址,所以對該變量進行屬性設置是可行的(未改變變量地址),如果想完全不可變化(包括屬性),那麼可以使用凍結Object.freeze

3.新增方法

(1)是否包含字符串

  • includes():返回布爾值,表示是否找到了參數字符串。
  • startsWith():返回布爾值,表示參數字符串是否在源字符串的頭部。
  • endsWith():返回布爾值,表示參數字符串是否在源字符串的尾部。
    這三個方法都支持第二個參數,表示開始搜索的位置。endsWith 的行爲與其他兩個方法有所不同,它針對前n個字符,而其他兩個方法針對從第n個位置直到字符串結束。

(2)重複字符串repeat()

repeat()返回一個新字符串,表示將原字符串重複n次。

(3)模版字符串

模板字符中,支持字符串插值:

  1. let first ='world';
  2. let last='中國';
  3. document.write(`Hello ${first} ${last}!`);
  4. // Hello world 中國!

(4)String.row()

若使用String.raw 作爲模板字符串的前綴,則模板字符串可以是原始(raw)的。反斜線也不再是特殊字符,\n 也不會被解釋成換行符:

  1. let raw =String.raw`Not a newline: \n`;
  2. document.write(raw ==='Not a newline: \\n');// true

(5)isFinite(),isNaN(),isInteger()

在Number對象上,新提供了Number.isFinite()Number.isNaN()兩個方法,用來檢查InfiniteNaN這兩個特殊值

Number.isInteger()用來判斷一個值是否爲整數。需要注意的是,在JavaScript內部,整數浮點數是同樣的儲存方法,所以3和3.0被視爲同一個值。

(6)Math對象新增方法

  • Math.trunc():去除一個數的小數部分,返回整數部分
  • Math.sign():判斷一個數到底是正數、負數、還是零。它返回五種值:參數爲正數,返回+1;參數爲負數,返回-1;參數爲0,返回0;參數爲-0,返回-0;其他值,返回NaN

  • Math.cbrt:計算一個數的立方根
  • Math.fround:返回一個數的單精度浮點數形式
  • Math.hypot:返回所有參數的平方和的平方根。
  • Math.expm1(x):返回ex - 1。
  • Math.log1p(x):返回1 + x的自然對數。如果x小於-1,返回NaN。
  • Math.log10(x):返回以10爲底的x的對數。如果x小於0,則返回NaN。
  • Math.log2(x):返回以2爲底的x的對數。如果x小於0,則返回NaN
4.數組方法
(1).Array.from方法用於將兩類對象轉爲真正的數組:類數組對象可遍歷的對象(包括ES6新增的數據結構Set和Map).任何有length屬性的對象,都可以通過Array.from方法轉爲數組
  1. let array =Array.from({0:"a",1:"b",2:"c", length:3});
  2. document.write(array);// [ "a", "b" , "c" ]
(2).Array.of方法用於將一組值,轉換爲數組。這個方法的主要目的,是彌補數組構造函數Array()的不足。因爲參數個數的不同,會導致Array()的行爲有差異。只有當參數個數不少於2個,Array()纔會返回由參數組成的新數組。
  1. Array(3)// [undefined, undefined, undefined]
  2. Array.of(3)// [3]
  3. Array.of(3).length // 1
(3).find方法,用於找出第一個符合條件的數組成員。它的參數是一個回調函數,所有數組成員依次執行該回調函數,直到找出第一個返回值爲true的成員,然後返回該成員。如果沒有符合條件的成員,則返回undefined
findIndex方法,用法與find方法非常類似,返回第一個符合條件的數組成員的位置,如果所有成員都不符合條件,則返回-1。
  1. let array =[1,5,10,15].find(function(value, index, arr){
  2. return value >9;
  3. })
  4. document.write(array);// 10
(4).fill()使用給定值,填充一個數組。fill方法用於空數組的初始化非常方便。但是如果數組中已有元素,會被全部抹去。fill()還可以接受第二個和第三個參數,用於指定填充的起始位置結束位置
(5).遍歷數組新方法,它們都返回一個遍歷器,可以用for...of循環進行遍歷,唯一的區別是keys()是對鍵名的遍歷、values()是對鍵值的遍歷,entries()是對鍵值對的遍歷。
  • entries()
  • keys()
  • values()
  1. for(let index of ['a','b'].keys()){
  2. document.write(index);//0,1
  3. }
  4. for(let elem of ['a','b'].values()){
  5. document.write(elem);//'a','b'
  6. }
  7. for(let [index, elem] of ['a','b'].entries()){
  8. document.write(index, elem);//0a,1b
  9. }
5.對象
ES6允許字面量定義對象時,用表達式作爲對象的屬性名,即把表達式放在方括號內。
(1).Object.is()用來比較兩個值是否嚴格相等。它與嚴格比較運算符(===)的行爲基本一致,不同之處只有兩個:一是+0不等於-0,二是NaN等於自身。
(2).Object.assign方法用來將源對象(source)的所有可枚舉屬性,複製到目標對象(target)。它至少需要兩個對象作爲參數,第一個參數是目標對象,後面的參數都是源對象。只要有一個參數不是對象,就會拋出TypeError錯誤。
注意,如果目標對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆蓋前面的屬性。
  1. var target={name:'張三'}
  2. var source={age:'19',sex:'男'}
  3. Object.assign(target, source1, source2); {"name":"張三","age":"19","sex":"男"}
(3).ES6引入了一種新的原始數據類型Symbol,表示獨一無二的ID。凡是屬性名屬於Symbol類型,就都是獨一無二的,可以保證不會與其他屬性名產生衝突。

注意,Symbol函數前不能使用new命令,否則會報錯。這是因爲生成的Symbol是一個原始類型的值,不是對象

Symbol類型的值不能與其他類型的值進行運算,會報錯。但是,Symbol類型的值可以轉爲字符串。

(4).Proxy 內置的一個代理工具,使用他可以在對象處理上加一層屏障,new Proxy()表示生成一個Proxy實例,它的target參數表示所要攔截的目標對象,handler參數也是一個對象,用來定製攔截行爲。
  1. var proxy =newProxy(target, handler)
6.函數
(1)函數綁定函數綁定運算符是並排的兩個雙引號(::),雙引號左邊是一個對象,右邊是一個函數。該運算符會自動將左邊的對象,作爲上下文環境(即this對象),綁定到右邊的函數上面。
  1. let log =::console.log;
  2. // 等同於var log = console.log.bind(console);
  3. foo::bar;
  4. // 等同於bar.call(foo);
  5. foo::bar(...arguments);
  6. // 等同於bar.apply(foo, arguments);
(2).箭頭函數是使用=>語法的函數簡寫形式。同時支持表達式體語句體。與(普通的)函數所不同的是,箭頭函數和其上下文中的代碼共享同一個具有詞法作用域的this
var array = [1, 2, 3];//傳統寫法
array.forEach(function(v, i, a) {console.log(v);});
//ES6
array.forEach(v = > console.log(v));
    箭頭函數使用時應注意:
  • 函數體內的this對象,綁定定義時所在的對象,而不是使用時所在的對象。
  • 不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。
  • 不可以使用arguments對象,該對象在函數體內不存在。

上面三點中,第一點尤其值得注意。this對象的指向是可變的,但是在箭頭函數中,它是固定的。

(3).尾調用優化尾調用是指某個函數的最後一步是調用另一個函數。尾調用由於是函數的最後一步操作,所以不需要保留外層函數的調用記錄,因爲調用位置、內部變量等信息都不會再用到了,只要直接用內層函數的調用記錄,取代外層函數的調用記錄就可以了。“尾調用優化”Tail call optimization),即只保留內層函數的調用幀,這樣可以節省內存。
7.Set
數據結構Set類似於數組,但是成員的值都是唯一的,沒有重複的值,Set函數可以接受一個數組作爲參數,用來初始化向Set加入值的時候,不會發生類型轉換,所以5“5”是兩個不同的值.

(1).Set結構實例的屬性:

  • Set.prototype.constructor:構造函數,默認就是Set函數。
  • Set.prototype.size:返回Set實例的成員總數。

(2).操作方法:

  • add(value):添加某個值,返回Set結構本身。
  • delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。
  • has(value):返回一個布爾值,表示該值是否爲Set的成員。
  • clear():清除所有成員,沒有返回值。

(3).遍歷方法:

  • keys():返回一個鍵名的遍歷器
  • values():返回一個鍵值的遍歷器
  • entries():返回一個鍵值對的遍歷器
  • forEach():使用回調函數遍歷每個成員
  1. let set=newSet(['red','green','blue']);
  2. for( let item of set.keys()){
  3. document.write(item);
  4. }
  5. for( let item of set.values()){
  6. document.write(item);
  7. }
  8. for( let item of set.entries()){
  9. document.write(item);
  10. }//["red", "red"]["green", "green"]["blue", "blue"]
  11. set.forEach(function(item){
  12. document.write(item);
  13. })

8.Map

Map 是一個“超對象”,其 key 除了可以是 String 類型之外,還可以爲其他類型(如:對象),他的方法和 Set 差不多:

  • size:返回成員總數。
  • set(key, value):設置key所對應的鍵值,然後返回整個Map結構。如果key已經有值,則鍵值會被更新,否則就新生成該鍵。
  • get(key):讀取key對應的鍵值,如果找不到key,返回undefined
  • has(key):返回一個布爾值,表示某個鍵是否在Map數據結構中。
  • delete(key):刪除某個鍵,返回true。如果刪除失敗,返回false。
  • clear():清除所有成員。
  • keys():返回鍵名的遍歷器。
  • values():返回鍵值的遍歷器。
  • entries():返回所有成員的遍歷器。

9.Iterator遍歷器

遍歷器(Iterator就是統一的接口機制,來處理所有不同的數據結構。

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

Iterator的遍歷過程

  • 創建一個指針,指向當前數據結構的起始位置。也就是說,遍歷器的返回值是一個指針對象。
  • 第一次調用指針對象的next方法,可以將指針指向數據結構的第一個成員。
  • 第二次調用指針對象的next方法,指針就指向數據結構的第二個成員。
  • 調用指針對象的next方法,直到它指向數據結構的結束位置。

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

遍歷器返回的指針對象除了具有next方法,還可以具有return方法和throw方法。其中,next方法是必須部署的,return方法和throw方法是否部署是可選的

return方法的使用場合是,如果for...of循環提前退出(通常是因爲出錯,或者有break語句或continue語句),就會調用return方法。如果一個對象在完成遍歷前,需要清理或釋放資源,就可以部署return方法。

throw方法主要是配合Generator函數使用,一般的遍歷器用不到這個方法。

10.Generator

Generator函數是一個函數的內部狀態的遍歷器(也就是說,Generator函數是一個狀態機)。形式上,Generator函數是一個普通函數,但是有兩個特徵。

  • 一是,function命令與函數名之間有一個星號*
  • 二是,函數體內部使用yield語句,定義遍歷器的每個成員,即不同的內部狀態。
  1. function* helloWorldGenerator(){
  2. yield'hello';
  3. yield'world';
  4. return'ending';
  5. }
  6. var hw = helloWorldGenerator();
  7. hw.next()// { value: 'hello', done: false }
  8. hw.next()// { value: 'world', done: false }
  9. hw.next()// { value: 'ending', done: true }
  10. hw.next()// { value: undefined, done: true }

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

    yield語句本身沒有返回值,或者說總是返回undefinednext方法可以帶一個參數,該參數就會被當作上一個yield語句的返回值。

        for...of循環可以自動遍歷Generator函數,且此時不再需要調用next方法。注意:一旦next方法的返回對象的done屬性爲true,for...of循環就會中止,且不包含該返回對象,所以return語句返回的對象,不包括在for...of循環之中。

    Generator 函數內部還可以部署錯誤處理代碼,捕獲函數體外拋出的錯誤。使用指針對象的 throw 方法拋出的錯誤,可以被函數體內的 try ... catch 代碼塊捕獲。這意味着,出錯的代碼與處理錯誤的代碼,實現了時間和空間上的分離,這對於異步編程無疑是很重要的。

11.Promise

所謂Promise,就是一個對象,用來傳遞異步操作的消息。

Promise對象有以下兩個特點:

  • 對象的狀態不受外界影響。Promise對象代表一個異步操作,有三種狀態:Pending(進行中)、Resolved(已完成,又稱Fulfilled)和Rejected(已失敗)。只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
  • 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise對象的狀態改變,只有兩種可能:Pending變爲Resolved和從Pending變爲Rejected只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果。就算改變已經發生了,你再對Promise對象添加回調函數,也會立即得到這個結果。這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。

        有了Promise對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise對象提供統一的接口,使得控制異步操作更加容易。

Promise也有一些缺點:

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

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

  1. //創建promise
  2. var promise =newPromise(function(resolve, reject){
  3. // 進行一些異步或耗時操作
  4. if(/*如果成功 */){
  5. resolve("Stuff worked!");
  6. }else{
  7. reject(Error("It broke"));
  8. }
  9. });
  10. //綁定處理程序
  11. promise.then(function(result){
  12. //promise成功的話會執行這裏
  13. document.write(result);// "Stuff worked!"
  14. },function(err){
  15. //promise失敗會執行這裏
  16. document.write(err);// Error: "It broke"
  17. });
  • resolve函數的作用是,將Promise對象的狀態從“未完成”變爲“成功”(即從Pending變爲Resolved),在異步操作成功時調用,並將異步操作的結果,作爲參數傳遞出去;
  • reject函數的作用是,將Promise對象的狀態從“未完成”變爲“失敗”(即從Pending變爲Rejected),在異步操作失敗時調用,並將異步操作報出的錯誤,作爲參數傳遞出去。

Promise實例具有then方法,也就是說,then方法是定義在原型對象,作用是爲Promise實例添加狀態改變時的回調函數。

then方法兩個參數:

  • Resolved狀態的回調函數;
  • Rejected狀態的回調函數(可選)。

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

  1. getJSON("/posts.json").then(function(json){
  2. return json.post;
  3. }).then(function(post){
  4. // ...
  5. });

上面的代碼使用then方法,依次指定了兩個回調函數。第一個回調函數完成以後,會將返回結果作爲參數,傳入第二個回調函數。

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

  1. getJSON("/posts.json").then(function(posts){
  2. // ...
  3. }).catch(function(error){
  4. // 處理前一個回調函數運行時發生的錯誤
  5. document.write('發生錯誤!', error);
  6. });

getJSON方法返回一個Promise對象,如果該對象狀態變爲Resolved,則會調用then方法指定的回調函數;如果異步操作拋出錯誤,狀態就會變爲Rejected,就會調用catch方法指定的回調函數,處理這個錯誤。

  1. var promise =newPromise(function(resolve, reject){
  2. thrownewError('test')
  3. });
  4. promise.catch(function(error){ document.write(error)});
  5. // Error: test

上面代碼中,Promise拋出一個錯誤,就被catch方法指定的回調函數捕獲。

Promise對象的錯誤具有“冒泡”性質,會一直向後傳遞,直到被捕獲爲止。也就是說,錯誤總是會被下一個catch語句捕獲。

  1. getJSON("/post/1.json").then(function(post){
  2. return getJSON(post.commentURL);
  3. }).then(function(comments){
  4. // some code
  5. }).catch(function(error){
  6. // 處理前面三個Promise產生的錯誤
  7. });

上面代碼中,一共有三個Promise對象:一個由getJSON產生,兩個由then產生。它們之中任何一個拋出的錯誤,都會被最後一個catch捕獲。

Promise.all方法用於將多個Promise實例,包裝成一個新的Promise實例。

  1. var p =Promise.all([p1,p2,p3]);

上面代碼中,Promise.all方法接受一個數組作爲參數,p1、p2、p3都是Promise對象的實例。(Promise.all方法的參數不一定是數組,但是必須具有iterator接口,且返回的每個成員都是Promise實例。)

p的狀態由p1、p2、p3決定,分成兩種情況。

  • 只有p1、p2、p3的狀態都變成fulfilled,p的狀態纔會變成fulfilled,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回調函數。
  • 只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。

Promise.race方法同樣是將多個Promise實例,包裝成一個新的Promise實例。

  1. var p =Promise.race([p1,p2,p3]);

上面代碼中,只要p1、p2、p3之中有一個實例率先改變狀態,p的狀態就跟着改變。那個率先改變的Promise實例的返回值,就傳遞給p的回調函數。

如果Promise.all方法和Promise.race方法的參數,不是Promise實例,就會先調用Promise.resolve方法,將現有對象轉爲Promise對象,如果Promise.resolve方法的參數,不是具有then方法的對象(又稱thenable對象),則返回一個新的Promise對象,且它的狀態爲Resolved

  1. var p =Promise.resolve('Hello');
  2. p.then(function(s){
  3. document.write(s)
  4. });
  5. // Hello

由於字符串Hello不屬於異步操作(判斷方法是它不是具有then方法的對象),返回Promise實例的狀態從一生成就是Resolved,所以回調函數會立即執行。

Promise.reject(reason)方法也會返回一個新的Promise實例,該實例的狀態爲rejected。Promise.reject方法的參數reason,會被傳遞給實例的回調函數。

  1. var p =Promise.reject('出錯了');
  2. p.then(null,function(s){
  3. document.write(s)
  4. });// 出錯了

上面代碼生成一個Promise對象的實例p,狀態爲rejected,回調函數會立即執行

12.Generator函數與Promise結合

使用Generator函數管理流程,遇到異步操作的時候,通常返回一個Promise對象

  1. function getFoo (){
  2. returnnewPromise(function(resolve, reject){
  3. resolve('foo');
  4. });
  5. }
  6. var g =function*(){
  7. try{
  8. var foo =yield getFoo();
  9. document.write(foo);
  10. }catch(e){
  11. document.write(e);
  12. }
  13. };
  14. function run (generator){
  15. var it = generator();
  16. function go(result){
  17. if(result.done)return result.value;
  18.  
  19. return result.value.then(function(value){
  20. return go(it.next(value));
  21. },function(error){
  22. return go(it.throw(value));
  23. });
  24. }
  25. go(it.next());
  26. }
  27. run(g);

上面代碼的Generator函數g之中,有一個異步操作getFoo,它返回的就是一個Promise對象。函數run用來處理這個Promise對象,並調用下一個next方法。

13.Class

ES6提供了更接近傳統語言的寫法,引入了Class(類)這個概念,作爲對象的模板。通過class關鍵字,可以定義類。

  1. //定義類
  2. classPoint{
  3. constructor(x, y){
  4. this.x = x;
  5. this.y = y;
  6. }
  7. toString(){
  8. return'('+this.x+', '+this.y+')';
  9. }
  10. }

上面代碼定義了一個“類”,可以看到裏面有一個constructor方法,這就是構造方法,而this關鍵字則代表實例對象。

constructor方法是類的默認方法,通過new命令生成對象實例時,自動調用該方法。

(1).class的繼承

Class之間可以通過extends關鍵字,實現繼承。子類會繼承父類的屬性和方法。

  1. classColorPointextendsPoint{
  2. constructor(x, y, color){
  3. this.color = color;// ReferenceError
  4. super(x, y);
  5. this.color = color;// 正確
  6. }
  7. }

注意:ColorPoint繼承了父類Point,但是它的構造函數必須調用super方法,super方法必須放在第一行。

在Class內部可以使用getset關鍵字,對某個屬性設置存值函數和取值函數。

(2).class的靜態方法

類相當於實例的原型,所有在類中定義的方法,都會被實例繼承。如果在一個方法前,加上static關鍵字,就表示該方法不會被實例繼承,而是直接通過類來調用,這就稱爲“靜態方法”。父類的靜態方法,可以被子類繼承。

  1. classFoo{
  2. static classMethod(){
  3. return'hello';
  4. }
  5. }
  6. Foo.classMethod()// 'hello'
  7. var foo =newFoo();
  8. foo.classMethod()
  9. // TypeError: undefined is not a function

(3).new.target屬性

new是從構造函數生成實例的命令。ES6爲new命令引入了一個new.target屬性,(在構造函數中)返回new命令作用於的那個構造函數。如果構造函數不是通過new命令調用的,new.target會返回undefined,因此這個屬性可以用來確定構造函數是怎麼調用的。

  • Class內部調用new.target,返回當前Class。
  • 子類繼承父類時,new.target會返回子類。

(4).修飾器

修飾器(Decorator)是一個表達式,用來修改類的行爲。這是ES7的一個提案,目前Babel轉碼器已經支持。修飾器對類的行爲的改變,是代碼編譯時發生的,而不是在運行時。這意味着,修飾器能在編譯階段運行代碼。

  1. function testable(target){
  2. target.isTestable =true;
  3. }
  4. @testable
  5. classMyTestableClass{}
  6. console.log(MyTestableClass.isTestable)// true

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

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

  1. @decorator
  2. class A {}
  3. // 等同於
  4. class A {}
  5. A = decorator(A)|| A;

修飾器函數可以接受三個參數,依次是目標函數屬性名該屬性的描述對象。後兩個參數可省略。testable函數的參數target,就是所要修飾的對象。如果希望修飾器的行爲,能夠根據目標對象的不同而不同,就要在外面再封裝一層函數。

  1. function testable(isTestable){
  2. returnfunction(target){
  3. target.isTestable = isTestable;
  4. }
  5. }
  6. @testable(true)classMyTestableClass(){}
  7. document.write(MyTestableClass.isTestable)// true
  8.  
  9. @testable(false)classMyClass(){}
  10. document.write(MyClass.isTestable)// false

如果想要爲類的實例添加方法,可以在修飾器函數中,爲目標類的prototype屬性添加方法。

  1. function testable(target){
  2. target.prototype.isTestable =true;
  3. }
  4. @testable
  5. classMyTestableClass(){}
  6.  
  7. let obj =newMyClass();
  8.  
  9. document.write(obj.isTestable)// true

14.模塊(module)

模塊功能主要由兩個命令構成:exportimport

  • export命令用於用戶自定義模塊,規定對外接口;
  • import命令用於輸入其他模塊提供的功能,同時創造命名空間(namespace),防止函數名衝突。

ES6允許將獨立的JS文件作爲模塊,允許一個JavaScript腳本文件調用另一個腳本文件。ES6支持多重加載,即所加載的模塊中又加載其他模塊。

  1. // profile.js
  2. var firstName ='Michael';
  3. var lastName ='Jackson';
  4. var year =1958;
  5. export{firstName, lastName, year};

  6. // main.js
  7. import{firstName, lastName, year}from'./profile';
  8.  
  9. function sfirsetHeader(element){
  10. element.textContent = firstName +' '+ lastName;
  11. }

import命令接受一個對象(用大括號表示),裏面指定要從其他模塊導入的變量名。大括號裏面的變量名,必須與被導入模塊(profile.js)對外接口的名稱相同。

module命令可以取代import語句,達到整體輸入模塊的作用。module命令後面跟一個變量,表示輸入的模塊定義在該變量上。

  1. module profile from './profile';

爲加載模塊指定默認輸出,使用export default命令。其他模塊加載該模塊時,import命令可以爲該匿名函數指定任意名字。

  1. // export-default.js
  2. exportdefaultfunction(){
  3. document.write('foo');
  4. }
  5. // import-default.js
  6. import customName from'./export-default';
  7. customName();// 'foo'

上面代碼的import命令,可以用任意名稱指向export-default.js輸出的方法。需要注意的是,這時import命令後面,不使用大括號。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章