1. 高階函式
高階函式就是那種輸入引數裡面有一個或者多個函式,輸出也是函式的函式,這個在js裡面主要是利用閉包實現的,最簡單的就是經常看到的在一個函式內部輸出另一個函式,比如
var test = function() {
return function() {}
}
這個主要是利用閉包來保持著作用域:
var add = function() {
var num = 0;
return function(a) {
return num = num + a;
}
}
add()(1); // 1
add()(2); // 2
這裡的兩個add()(1)和add()(2)不會互相影響,可以理解為每次執行add函式後返回的都是不同的匿名函式,就是每次add執行後return的function其實都是不同的,所以執行結果也是不會影響的。
如果換一種寫法,比如:
var add = function() {
var num = 0;
return function(a) {
return num = num + a;
}
}
var adder = add();
adder(1); // 1
adder(2); // 3
這樣的話就會在之前運算結果基礎上繼續運算,意思就是這兩個 adder 執行的時候都是呼叫的同一個 num
2. 高階函式實現快取(備忘模式)
比如有個函式:
var add = function(a) {
return a + 1;
}
每次執行add(1)
的時候都會輸出2
,但是輸入1
每次還是會計算一下1+1
,如果是開銷很大的操作的話就比較消耗效能了,這裡其實可以對這個計算進行一次快取。
所以這裡可以利用高階函式的思想來實現一個簡單的快取,我可以在函式內部用一個物件儲存輸入的引數,如果下次再輸入相同的引數,那就比較一下物件的屬性,把值從這個物件裡面取出來。
const memorize = function(fn) {
const cache = {}
return function(...args) {
const _args = JSON.stringify(args)
return cache[_args] || (cache[_args] = fn.apply(fn, args))
}
}
const add = function(a) {
return a + 1
}
const adder = memorize(add)
adder(1) // 2 cache: { '[1]': 2 }
adder(1) // 2 cache: { '[1]': 2 }
adder(2) // 3 cache: { '[1]': 2, '[2]': 3 }
用JSON.stringify
把傳給 adder 函式的引數變成了字串,並且把它當做 cache 的 key,將 add 函式執行的結果當做 value 傳到了 cache 裡面,這樣 memorize 的匿名函式執行的時候會返回cache[_args]
,如果cache[_args]
不存在的話就返回fn.apply(fn,args),把fn.apply(fn, arguments)
賦值給cache[_args]
並返回。
注意:cache不可以是Map
,因為Map的鍵是使用===
比較的,[1]!==[1]
,因此即使傳入相同的物件或者陣列,那麼還是被存為不同的鍵。
const memorize = function(fn) { // X 錯誤示範
const cache = new Map()
return function(...args) {
return cache.get(args) || cache.set(args, fn.apply(fn, args)).get(args)
}
}
const add = function(a) {
return a + 1
}
const adder = memorize(add)
adder(1) // 2 cache: { [ 1 ] => 2 }
adder(1) // 2 cache: { [ 1 ] => 2, [ 1 ] => 2 }
adder(2) // 3 cache: { [ 1 ] => 2, [ 1 ] => 2, [ 2 ] => 3 }
本文是系列文章,可以相互參考印證,共同進步~
網上的帖子大多深淺不一,甚至有些前後矛盾,在下的文章都是學習過程中的總結,如果發現錯誤,歡迎留言指出~
參考: <JavaScript模式>P78