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
問:舉一些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