Javascript函數緩存的實現及應用場景
一、是什么
函數緩存,就是將函數運算過的結果進行緩存
本質上就是用空間(緩存存儲)換時間(計算過程)
常用于緩存數據計算結果和緩存對象
const add = (a,b) => a+b; const calc = memoize(add); // 函數緩存 calc(10,20);// 30 calc(10,20);// 30 緩存
緩存只是一個臨時的數據存儲,它保存數據,以便將來對該數據的請求能夠更快地得到處理
二、如何實現
實現函數緩存主要依靠閉包、柯里化、高階函數,這里再簡單復習下:
閉包
閉包可以理解成,函數 + 函數體內可訪問的變量總和
(function() { var a = 1; function add() { const b = 2 let sum = b + a console.log(sum); // 3 } add() })()
add
函數本身,以及其內部可訪問的變量,即 a = 1
,這兩個組合在?起就形成了閉包
柯里化
把接受多個參數的函數轉換成接受一個單一參數的函數
// 非函數柯里化 var add = function (x,y) { return x+y; } add(3,4) //7 ? // 函數柯里化 var add2 = function (x) { //**返回函數** return function (y) { return x+y; } } add2(3)(4) //7
將一個二元函數拆分成兩個一元函數
高階函數
通過接收其他函數作為參數或返回其他函數的函數
function foo(){ var a = 2; ? function bar() { console.log(a); } return bar; } var baz = foo(); baz();//2
函數 foo
如何返回另一個函數 bar
,baz
現在持有對 foo
中定義的bar
函數的引用。由于閉包特性,a
的值能夠得到
下面再看看如何實現函數緩存,實現原理也很簡單,把參數和對應的結果數據存在一個對象中,調用時判斷參數對應的數據是否存在,存在就返回對應的結果數據,否則就返回計算結果
如下所示
const memoize = function (func, content) { let cache = Object.create(null) content = content || this return (...key) => { if (!cache[key]) { cache[key] = func.apply(content, key) } return cache[key] } }
調用方式也很簡單
const calc = memoize(add); const num1 = calc(100,200) const num2 = calc(100,200) // 緩存得到的結果
過程分析:
在當前函數作用域定義了一個空對象,用于緩存運行結果
運用柯里化返回一個函數,返回的函數由于閉包特性,可以訪問到
cache
然后判斷輸入參數是不是在
cache
的中。如果已經存在,直接返回cache
的內容,如果沒有存在,使用函數func
對輸入參數求值,然后把結果存儲在cache
中
三、應用場景
雖然使用緩存效率是非常高的,但并不是所有場景都適用,因此千萬不要極端的將所有函數都添加緩存
以下幾種情況下,適合使用緩存:
對于昂貴的函數調用,執(zhí)行復雜計算的函數
對于具有有限且高度重復輸入范圍的函數
對于具有重復輸入值的遞歸函數
對于純函數,即每次使用特定輸入調用時返回相同輸出的函數
new操作符具體干了什么?
一、是什么
在JavaScript
中,new
操作符用于創(chuàng)建一個給定構造函數的實例對象
例子
function Person(name, age){ this.name = name; this.age = age; } Person.prototype.sayName = function () { console.log(this.name) } const person1 = new Person('Tom', 20) console.log(person1) // Person {name: "Tom", age: 20} t.sayName() // 'Tom'
從上面可以看到:
new
通過構造函數Person
創(chuàng)建出來的實例可以訪問到構造函數中的屬性new
通過構造函數Person
創(chuàng)建出來的實例可以訪問到構造函數原型鏈中的屬性(即實例與構造函數通過原型鏈連接了起來)
現在在構建函數中顯式加上返回值,并且這個返回值是一個原始類型
function Test(name) { this.name = name return 1 } const t = new Test('xxx') console.log(t.name) // 'xxx' 可以發(fā)現,構造函數中返回一個原始值,然而這個返回值并沒有作用 下面在構造函數中返回一個對象 function Test(name) { this.name = name console.log(this) // Test { name: 'xxx' } return { age: 26 } } const t = new Test('xxx') console.log(t) // { age: 26 } console.log(t.name) // 'undefined'
從上面可以發(fā)現,構造函數如果返回值為一個對象,那么這個返回值會被正常使用
二、流程
從上面介紹中,我們可以看到new
關鍵字主要做了以下的工作:
創(chuàng)建一個新的對象
obj
將對象與構建函數通過原型鏈連接起來
將構建函數中的
this
綁定到新建的對象obj
上根據構建函數返回類型作判斷,如果是原始值則被忽略,如果是返回對象,需要正常處理
舉個例子:
function Person(name, age){ this.name = name; this.age = age; } const person1 = new Person('Tom', 20) console.log(person1) // Person {name: "Tom", age: 20} t.sayName() // 'Tom'
三、手寫new操作符
現在我們已經清楚地掌握了new
的執(zhí)行過程
那么我們就動手來實現一下new
function mynew(Func, ...args) { // 1.創(chuàng)建一個新對象 const obj = {} // 2.新對象原型指向構造函數原型對象 obj.__proto__ = Func.prototype // 3.將構建函數的this指向新對象 let result = Func.apply(obj, args) // 4.根據返回值判斷 return result instanceof Object ? result : obj }
測試一下
function mynew(func, ...args) { const obj = {} obj.__proto__ = func.prototype let result = func.apply(obj, args) return result instanceof Object ? result : obj } function Person(name, age) { this.name = name; this.age = age; } Person.prototype.say = function () { console.log(this.name) } ? let p = mynew(Person, "huihui", 123) console.log(p) // Person {name: "huihui", age: 123} p.say() // huihui
可以發(fā)現,代碼雖然很短,但是能夠模擬實現new
到此這篇關于Javascript函數緩存的實現及應用場景的文章就介紹到這了,更多相關Javascript函數緩存內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
基于Bootstrap使用jQuery實現輸入框組input-group的添加與刪除
這篇文章主要介紹了基于Bootstrap使用jQuery實現輸入框組input-group的添加與刪除的相關資料,需要的朋友可以參考下2016-05-05使用Chrome調試JavaScript的斷點設置和調試技巧
這篇文章主要介紹了使用Chrome調試JavaScript的斷點設置和調試技巧,需要的朋友可以參考下2014-12-12