一、事件迴圈機制的理解
test();//按秒輸出5個5
function test() {
for (var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 1000 * i);//for迴圈裡面新增非同步操作
}
}
test();//分別按秒輸出0 1 2 3 4
function test() {
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 1000 * i);//for迴圈裡面新增非同步操作
}
}
首先,先解釋一下產生不同的結果的原因:
我們知道,var跟let的核心區別主要就是作用域的問題。
詳細解釋:
因為let i 宣告的是區塊變數,每個i只能存活到大括號結束,並不會把後面for迴圈的 i 值賦給前面的setTimeout中的i;
而var i 則是區域性變數,這個 i 的生命週期不受for迴圈的大括號限制;
這道面試題還涉及到了JavaScript中的事件迴圈機制,稍微重點講解一下:
我們知道,JavaScript是單執行緒的(一次只能執行一個任務),那單執行緒是如何做到非同步的呢?
在大學裡,資料結構中,我們學過棧(先進後出)和佇列(先進先出)這兩種資料結構吧。
js引擎中,便用到了,棧中存放執行的程式碼,佇列中存放多個任務。
事件迴圈機制(Event Loop):js會檢查棧中是否為空,為空的話,將佇列中的任務加入到這個棧中。
這樣的話,還是不能實現非同步的,畢竟js是單執行緒,一次只能執行一個任務,即使有棧和佇列,還是不能實現非同步的,那非同步到底是怎麼實現的呢?
這裡需要了解一下回撥函式,舉個例子,jQuery中Ajax非同步請求我們經常用到吧,其中的success就是個回撥函式。
其實呢,如果是個非同步操作的話,當放入到佇列中後,它會註冊一個回撥事件,然後再執行這個回撥函式,如此,便實現了非同步。
舉個例子吧:
var x = 6;
console.log(x);
var pro = new Promise(function (reslove, reject) {
var i = 3;
setTimeout(() => {
i++;
reslove(i);
}, 3000);
});
pro.then(function (data) {
console.log(data);
});
分析:前兩行程式碼定義變數便列印出來,接下來便是個非同步操作,便是通過resolve回撥函式來真正實現非同步的。
二、函式柯里化
乍一看,給人一種很是高大上的感覺。這東西呢,理解起來真的是雲裡霧裡的。
柯里化,是函數語言程式設計裡面的一個概念。
說下初步的理解吧
function add(num1, num2) {
return num1 + num2;
}
// 柯里化的思想
function curriedAdd(num2) {
return add(5, num2);
}
console.log(add(2, 3));//5 寫好一個函式,然後在需要的時候呼叫這個函式。這便是函數語言程式設計的基本思想。
console.log(curriedAdd(3));//8
正如上面的程式碼,本來add方法裡面需要傳遞2個引數,函式柯里化後,類似curriedAdd只需要傳遞1個引數即可。這便是所謂的函式柯里化。當然,這上面並不夠標準,只是表達了柯里化的思想。
function add(num1, num2) {
return num1 + num2;
}
//柯里化方法
function curry(fn) {
var args = Array.prototype.slice.call(arguments, 1);
return function () {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null, finalArgs);
}
}
var curriedAdd = curry(add, 5);//函式柯里化
console.log(curriedAdd(3));//8
那函式柯里化的好處是什麼呢?既然提出了這個概念,沒有好處是不可能滴!
簡單來說就是為了簡便,呼叫函式的時候,只需傳遞一個引數。當然了,我理解得還不夠深,沒達到那種透徹的地步,仍然有點雲裡霧裡的感覺,沒充分地體會到函式柯里化的好處。
總結
發現自己還有很長的一段路要走!鑽的還是不夠深!不夠精!