谁能解释下面使用 JS 和记忆技术的代码中发生了什么



如果有人能以简单的方式逐步解释这里发生的事情,那将非常有帮助。我知道memoize()正在缓存函数,但我需要更好的理解。谢谢!

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]

缓存键是空对象,因为没有任何东西作为参数传递给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。

因此,从本质上讲,这样做是确保任何给定的函数对于您传递给它的任何给定参数集只执行一次。

memoize 函数在为给定函数执行时,将返回一个在上下文中具有该缓存的新函数。 它要做的第一件事是创建参数对象的 JSON 字符串表示形式,以用作该特定结果的唯一键。

然后,它使用 null 合并运算符将该缓存值设置为自身(如果它已存在(或应用了这些参数的注入函数的结果。

如果您实际命名您正在使用的所有函数,这将更有意义:

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 运行。 这将创建一个"{"0": 1, "1": 2}"的 cacheKey,然后设置cache[cacheKey] = add.apply(add, [1 ,2])(实际上,当然,在里面它认为"add"是"injectedFunction"。

下次运行 memoizeAdd(1,2( 时,你会得到相同的结果,即缓存中的 3,而无需再次运行 add(( 函数。

希望一切都有意义。

memoize()缓存函数是什么意思?这意味着函数不会被执行,而是返回缓存的结果。(纯(函数的结果始终基于其参数。如果调用具有相同参数的函数,它将返回相同的结果。这就是为什么我们可以将结果存储在cache对象中,参数(或str它的字符串表示(作为键,函数的结果作为值:

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

apply用于将函数 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。返回的函数在所谓的闭包中捕获这种事态。闭包是一种将局部变量的值与函数一起存储的方法。

最新更新