1. 程式人生 > >ES6的幾個問題,你都會嗎?

ES6的幾個問題,你都會嗎?

問:舉一些ES6對Number數字型別做的常用升級優化?

1、優化部分:
ES6在Number原型上新增了isFinite(), isNaN()方法,用來取代傳統的全域性isFinite(), isNaN()方法檢測數值是否有限、是否是NaN。ES5的isFinite(), isNaN()方法都會先將非數值型別的引數轉化為Number型別再做判斷,這其實是不合理的,最造成isNaN('NaN') === true的奇怪行為--'NaN'是一個字串,但是isNaN卻說這就是NaN。而Number.isFinite()和Number.isNaN()則不會有此類問題(Number.isNaN('NaN') === false)。(isFinite()同上)

2、升級部分:
ES6在Math物件上新增了Math.cbrt(),trunc(),hypot()等等較多的科學計數法運算方法,可以更加全面的進行立方根、求和立方根等等科學計算。

 

問:舉一些ES6對Object型別做的常用升級優化?(重要)

a. ES6在Object原型上新增了is()方法,做兩個目標物件的相等比較,用來完善'==='方法。'==='方法中NaN === NaN //false其實是不合理的,Object.is修復了這個小bug。(Object.is(NaN, NaN) // true)

b. ES6在Object原型上新增了getPrototypeOf()和setPrototypeOf()方法,用來獲取或設定當前物件的prototype物件。這個方法存在的意義在於,ES5中獲取設定prototype對像是通過proto

屬性來實現的,然而proto屬性並不是ES規範中的明文規定的屬性,只是瀏覽器各大產商“私自”加上去的屬性,只不過因為適用範圍廣而被預設使用了,再非瀏覽器環境中並不一定就可以使用,所以為了穩妥起見,獲取或設定當前物件的prototype物件時,都應該採用ES6新增的標準用法。

 

問:舉一些ES6對Function函式型別做的常用升級優化?(重要)

ES6新增了雙冒號運算子,用來取代以往的bind,call,和apply。

ES6新增了雙冒號運算子,用來取代以往的bind,call,和apply。

foo::bar;
// 等同於
bar.bind(foo);
 
foo::bar(...arguments);
// 等同於

問:Set是什麼,有什麼作用?

答: Set是ES6引入的一種類似Array的新的資料結構,Set例項的成員類似於陣列item成員,區別是Set例項的成員都是唯一,不重複的。這個特性可以輕鬆地實現陣列去重。

問:Proxy是什麼,有什麼作用?

答: Proxy是ES6新增的一個建構函式,可以理解為JS語言的一個代理,用來改變JS預設的一些語言行為,包括攔截預設的get/set等底層方法,使得JS的使用自由度更高,可以最大限度的滿足開發者的需求。比如通過攔截物件的get/set方法,可以輕鬆地定製自己想要的key或者value。下面的例子可以看到,隨便定義一個myOwnObj的key,都可以變成自己想要的函式。


function createMyOwnObj() {
    //想把所有的key都變成函式,或者Promise,或者anything
    return new Proxy({}, {
        get(target, propKey, receiver) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    let randomBoolean = Math.random() > 0.5;
                    let Message;
                    if (randomBoolean) {
                        Message = `你的${propKey}運氣不錯,成功了`;
                        resolve(Message);
                    } else {
                        Message = `你的${propKey}運氣不行,失敗了`;
                        reject(Message);
                    }
                }, 1000);
            });
        }
    });
}
 
let myOwnObj = createMyOwnObj();
 
myOwnObj.hahaha.then(result => {
    console.log(result) //你的hahaha運氣不錯,成功了
}).catch(error => {
    console.log(error) //你的hahaha運氣不行,失敗了
})
 
myOwnObj.wuwuwu.then(result => {
    console.log(result) //你的wuwuwu運氣不錯,成功了
}).catch(error => {
    console.log(error) //你的wuwuwu運氣不行,失敗了

問:Reflect是什麼,有什麼作用?

答:  Reflect是ES6引入的一個新的物件,他的主要作用有兩點,一是將原生的一些零散分佈在Object、Function或者全域性函式裡的方法(如apply、delete、get、set等等),統一整合到Reflect上,這樣可以更加方便更加統一的管理一些原生API。其次就是因為Proxy可以改寫預設的原生API,如果一旦原生API別改寫可能就找不到了,所以Reflect也可以起到備份原生API的作用,使得即使原生API被改寫了之後,也可以在被改寫之後的API用上預設的API。
 

問:Iterator是什麼,有什麼作用?(重要)

答: Iterator是ES6中一個很重要概念,它並不是物件,也不是任何一種資料型別。因為ES6新增了Set、Map型別,他們和Array、Object型別很像,Array、Object都是可以遍歷的,但是Set、Map都不能用for迴圈遍歷,解決這個問題有兩種方案,一種是為Set、Map單獨新增一個用來遍歷的API,另一種是為Set、Map、Array、Object新增一個統一的遍歷API,顯然,第二種更好,ES6也就順其自然的需要一種設計標準,來統一所有可遍歷型別的遍歷方式。Iterator正是這樣一種標準。或者說是一種規範理念。
就好像JavaScript是ECMAScript標準的一種具體實現一樣,Iterator標準的具體實現是Iterator遍歷器。Iterator標準規定,所有部署了key值為[Symbol.iterator],且[Symbol.iterator]的value是標準的Iterator介面函式(標準的Iterator介面函式: 該函式必須返回一個物件,且物件中包含next方法,且執行next()能返回包含value/done屬性的Iterator物件)的物件,都稱之為可遍歷物件,next()後返回的Iterator物件也就是Iterator遍歷器。

let arr = ['a','b','c'];

  let it = arr[Symbol.iterator]();

  iter.next(); // {value:'a',done:false}

  iter.next(); // {value:'b',done:false}

  iter.next(); // {value:'c',done:false}

  iter.next(); // {value:undefined,done:true}

Generator函式是什麼,有什麼作用?

答: 如果說JavaScript是ECMAScript標準的一種具體實現、Iterator遍歷器是Iterator的具體實現,那麼Generator函式可以說是Iterator介面的具體實現方式。
執行Generator函式會返回一個遍歷器物件,每一次Generator函式裡面的yield都相當一次遍歷器物件的next()方法,並且可以通過next(value)方法傳入自定義的value,來改變Generator函式的行為。
Generator函式可以通過配合Thunk 函式更輕鬆更優雅的實現非同步程式設計和控制流管理。

1、非同步操作的同步化表達

Generator函式的暫停執行的效果,意味著可以把非同步操作寫在yield語句裡面,等到呼叫next方法時再往後執行。這實際上等同於不需要寫回調函數了,因為非同步操作的後續操作可以放在yield語句下面,反正要等到呼叫next方法時再執行。所以,Generator函式的一個重要實際意義就是用來處理非同步操作,改寫回調函式。

複製程式碼
function* loadUI() {
  showLoadingScreen();
  yield loadUIDataAsynchronously();
  hideLoadingScreen();
}
var loader = loadUI();
// 載入UI
loader.next()

// 解除安裝UI
loader.next()
複製程式碼
2、控制流管理

如果有一個多步操作非常耗時,採用回撥函式,可能會寫成下面這樣。

複製程式碼
step1(function (value1) {
  step2(value1, function(value2) {
    step3(value2, function(value3) {
      step4(value3, function(value4) {
        // Do something with value4
      });
    });
  });
});
複製程式碼
採用Promise改寫上面的程式碼。

複製程式碼
Promise.resolve(step1)
  .then(step2)
  .then(step3)
  .then(step4)
  .then(function (value4) {
    // Do something with value4
  }, function (error) {
    // Handle any error from step1 through step4
  })
  .done();
複製程式碼
上面程式碼已經把回撥函式,改成了直線執行的形式,但是加入了大量Promise的語法。Generator函式可以進一步改善程式碼執行流程。

複製程式碼
function* longRunningTask(value1) {
  try {
    var value2 = yield step1(value1);
    var value3 = yield step2(value2);
    var value4 = yield step3(value3);
    var value5 = yield step4(value4);
    // Do something with value4
  } catch (e) {
    // Handle any error from step1 through step4
  }
}
複製程式碼
3、部署Iterator介面

利用Generator函式,可以在任意物件上部署Iterator介面。

複製程式碼
function* iterEntries(obj) {
  let keys = Object.keys(obj);
  for (let i=0; i < keys.length; i++) {
    let key = keys[i];
    yield [key, obj[key]];
  }
}

let myObj = { foo: 3, bar: 7 };

for (let [key, value] of iterEntries(myObj)) {
  console.log(key, value);
}

// foo 3
// bar 7
複製程式碼
4、作為資料結構

Generator可以看作是資料結構,更確切地說,可以看作是一個數組結構,因為Generator函式可以返回一系列的值,這意味著它可以對任意表達式,提供類似陣列的介面。

 

async函式是什麼,有什麼作用?

async函式可以理解為內建自動執行器的Generator函式語法糖,它配合ES6的Promise近乎完美的實現了非同步程式設計解決方案。

const getRepoData = () => {
  return new Promise((resolve, reject) => {
    request(options, (err, res, body) => {
      if (err) {
        reject(err);
      }
      resolve(body);
    });
  });
};

async function asyncFun() {
 try {
    const value = await getRepoData();
    // ... 和上面的yield類似,如果有多個非同步流程,可以放在這裡,比如
    // const r1 = await getR1();
    // const r2 = await getR2();
    // const r3 = await getR3();
    // 每個await相當於暫停,執行await之後會等待它後面的函式(不是generator)返回值之後再執行後面其它的await邏輯。
    return value;
  } catch (err) {
    console.log(err);
  }
}

 

日常前端程式碼開發中,有哪些值得用ES6去改進的程式設計優化或者規範?

1、常用箭頭函式來取代var self = this;的做法。

2、常用let取代var命令。

3、常用陣列/物件的結構賦值來命名變數,結構更清晰,語義更明確,可讀性更好。

4、在長字串多變數組合場合,用模板字串來取代字串累加,能取得更好地效果和閱讀體驗。

5、用Class類取代傳統的建構函式,來生成例項化物件。

6、在大型應用開發中,要保持module模組化開發思維,分清模組之間的關係,常用import、export方法。

 

參考:https://blog.csdn.net/sinat_17775997/article/details/85262253