2017-07-22 24 views
3

如果有人能夠以簡單的方式逐步解釋發生的事情,這將非常有幫助。我知道memoize()緩存的功能,但我需要更好的理解。謝謝!任何人都可以解釋下面使用JS和memoization技術的代碼中發生了什麼

var memoize = function (f) { 
    var cache = {}; 
    return function() { 
    var str = JSON.stringify(arguments); 
    cache[str] = cache[str] || f.apply(f, arguments); 
    return cache[str]; 
    }; 
}; 

var mUser = memoize(function(x){ 
    return function() { 
    return x; 
    }; 
}); 

var x = mUser(1); 
var y = mUser(2); 
console.log(x()); //1 
console.log(y()); //2 

編輯:我保留原始記錄。但發佈修改後的代碼和我對它的理解。我需要意見,如果我是對還是錯,以及一些解釋。

var memoize = function (injected) { 
    var cache = {}; 
    return function closure_with_access_to_cache() { 
    var str = JSON.stringify(arguments); 
    cache[str] = cache[str] || injected.apply(injected, arguments); 
    console.log(cache); 
    return cache[str]; 
    }; 
}; 

var memoizeUser = memoize (function injected(a) { 
    return function closure_with_access_to_a() { 
    return a; 
    }; 
}); 

memoizeUser(); 

讓我們嘗試回溯事情。

首先,當memoizeUser();語句正在執行時,memoizeUser表示的是什麼或者哪個函數首先被調用?

var memoizeUser = ...是一個函數表達式,意味着它不會被掛起。因此,memoize被調用。

但是,var memoize = ...也是一個函數表達式。仔細看一下,它是一個關閉closure_with_access_to_cache並在調用時接收傳遞給memoizeUser的參數。

在這個closure_with_access_to_cache裏面,第一次,cache是空的,所以injected.apply(injected, arguments)被執行並得到另一個關閉closure_with_access_to_a作爲返回值。該值存儲到cache,然後返回。因此,memoizeUser實際上變成了closure_with_access_to_aa等於傳遞給memoizeUser的值。

讓我們來看看一些調用和日誌。

console.log(memoizeUser()); 
{ '{}': [Function: closure_with_access_to_a] } 
[Function: closure_with_access_to_a] 

緩存關鍵是因爲沒有被作爲PARAM傳遞給memoizeUser()空對象。 memoizeUser()返回記錄的功能closure_with_access_to_a

console.log(memoizeUser()()); 
{ '{}': [Function: closure_with_access_to_a] } 
undefined 

memoizeUser()回報功能closure_with_access_to_a被稱爲和記錄不確定這是的a值作爲什麼傳遞給memoizeUser

memoizeUser(1); 
{ '{"0":1}': [Function: closure_with_access_to_a] } 

和上面一樣,除了a過的1

console.log(memoizeUser(1)()); 
{ '{"0":1}': [Function: closure_with_access_to_a] } 
1 

和上面一樣,除了價值有a 1.

+0

可能看看地圖s和其餘params,它使東西更加防彈... –

+0

@Jonasw感謝您的建議! –

回答

1

值所以基本上這樣做是確保任何給定函數僅會對你傳給它的任何給定的一組參數執行一次。

memoize函數在爲給定函數執行時,將返回一個新的函數,該函數在上下文中具有該緩存。它所做的第一件事是創建一個參數對象的JSON字符串表示形式,以用作該特定結果的唯一鍵。

然後它使用空合併運算符將該緩存值設置爲自身(如果它已經存在)或者將這些參數應用於注入函數的結果。

這使得更多的意義,如果你真正的名字你正在測試的功能:

function memoize(injectedFunction) { 
    var cache = {}; 
    return function memoizedFunction() { 
    // 'arguments' here is the arguments object for memoizedFunction. 
    var cacheKey= JSON.stringify(arguments); 

    // This is a logical OR which is null coalescing in JS. If cache[str] 
    // is null or undefined, the statement proceeds to call injectedFunction.apply. 
    // If it's not, then it returns whatever is stored there. 
    cache[cacheKey] = cache[cacheKey] || injectedFunction.apply(injectedFunction, arguments); 
    return cache[cacheKey]; 
    }; 
}; 

所以在本質上,考慮一個簡單的加法功能被注入:

function add(a, b) { return a + b; } 

var memoizedAdd = memoize(add); 

console.log(memoizedAdd(1, 2)); 

此時,memoizedAdd運行參數1,2。這會創建一個cacheKey "{\"0\": 1, \"1\": 2}",然後設置cache[cacheKey] = add.apply(add, [1 ,2])(實際上,它當然在那裏它認爲'add'爲'injectFunction'。

下一次運行memoizeAdd(1,2)時,會從緩存中獲得相同的3結果,而不會再次運行add()函數。

希望大家都有道理。

+0

@Paul感謝您花費的時間和精力。我編輯了我的問題,並添加了一些想法,以供進一步分析:)我猜是什麼讓它有點棘手是'memoizeUser'裏面的閉包 –

+0

我不知道你在問什麼。 – Paul

1

這是什麼意思memoize()緩存的功能?這意味着函數不會被執行,而是返回一個緩存的結果。 (純)函數的結果總是基於它的參數。如果您使用相同的參數調用一個函數,它將返回相同的結果。這就是爲什麼我們可以存儲在與該參數的cache對象作爲密鑰的結果(或str它的一個字符串化表示)和功能的值的結果是:

cache[str] = f.apply(f, arguments); 

apply用於to apply function f到陣列我們提供的參數,在這種情況下,我們的f函數被調用的所有參數。

cache[str] = cache[str] || f.apply(f, arguments); 

是爲cache[str]設置默認值的簡寫方法。如果未設置cache[str],則將調用函數f並存儲結果。

在你的例子中被記憶的函數也很有趣。它需要一個參數並返回一個函數。 xy是功能。您可以通過添加()(空參數列表)來調用它們。這就是爲什麼最後一行讀

console.log(x()); //1 
console.log(y()); //2 

在JavaScript中,如果你使用function關鍵字另一個函數裏面,你正在創建一個閉合。

由於關閉,局部變量(局部變量x)可以在從調用的函數返回後保持可訪問。

當以1作爲參數調用函數mUser時,局部變量x等於1.正在返回的函數在所謂的閉包中捕獲這種事態。閉包是將局部變量的值與函數一起存儲的一種方式。

+0

「重要的是要注意,memoize函數返回一個可以不帶參數調用的函數,這就是爲什麼最後一行讀取」,你在這一點上是不正確的。 「x」可以被稱爲w/o參數的原因是因爲在創建mUser時傳遞給memoize的函數,而不是因爲它被記憶。 – Paul

+0

@Paul完全正確。感謝您的輸入。我已經更新了我的答案。你能再看一遍嗎? – snwclone

+0

@snwclone謝謝你的回答! –

相關問題