Javascript 如何更正此缓存函数

Javascript 如何更正此缓存函数,javascript,ecmascript-6,Javascript,Ecmascript 6,我试图创建一个缓存函数,但即使在将缓存的值存储在变量中之后,它也总是触发结果未被缓存的条件 在我的代码中,我将结果存储在变量cachedValue中。 应该缓存的函数('foo')只有在参数('arg')中传递了新值时才应该调用 function cacheFunction(foo) { const cachedValue = []; return (arg) => { if (cachedValue[arg]) { return cachedValue[arg

我试图创建一个缓存函数,但即使在将缓存的值存储在变量中之后,它也总是触发结果未被缓存的条件

在我的代码中,我将结果存储在变量cachedValue中。 应该缓存的函数('foo')只有在参数('arg')中传递了新值时才应该调用

function cacheFunction(foo) {
  const cachedValue = [];
  return (arg) => {
    if (cachedValue[arg]) {
      return cachedValue[arg];
    }
    cachedValue[arg] = foo(arg);
    return cachedValue[arg];
  };
}

export { cacheFunction };
测试代码

import { cacheFunction } from './cacheFunction';

describe('cacheFunction', () => {
  it('should cache function results and not rerun the original callback if the same arguments are presented', () => {
    const foo = jest.fn();
    const myCachedFunction = cacheFunction(foo);
    myCachedFunction(true);
    myCachedFunction(true);
    myCachedFunction(true);
    myCachedFunction(true);
    myCachedFunction(true);
    myCachedFunction(10);
    myCachedFunction(10);
    myCachedFunction(10);
    myCachedFunction(10);
    myCachedFunction(10);
    expect(foo).toHaveBeenCalledTimes(2);
// It is called 10 times
  });
});

只需更换
if
语句检查:

if (cachedValue[arg]) {
   return cachedValue[arg];
}
将是:

if (cachedValue.hasOwnProperty(arg)) {
   return cachedValue[arg];
}
因为这些元素中的每一个都存储为
undefined
,所以第一个检查
if(cachedValue[arg])
返回
undefined
,在Javascript中被认为是
false

我认为,如果您使用对象而不是数组来实现此目的,那么也会更好

const cachedValue=[]

将是:

if (cachedValue.hasOwnProperty(arg)) {
   return cachedValue[arg];
}

constcachedValue={}

只要在检查语句时替换

if (cachedValue[arg]) {
   return cachedValue[arg];
}
将是:

if (cachedValue.hasOwnProperty(arg)) {
   return cachedValue[arg];
}
因为这些元素中的每一个都存储为
undefined
,所以第一个检查
if(cachedValue[arg])
返回
undefined
,在Javascript中被认为是
false

我认为,如果您使用对象而不是数组来实现此目的,那么也会更好

const cachedValue=[]

将是:

if (cachedValue.hasOwnProperty(arg)) {
   return cachedValue[arg];
}

constcachedValue={}

您的模拟函数错误
jest.fn
不带参数,只提供一个模拟函数,返回
未定义的
。您需要一个基于收到的参数返回某些内容的函数。也许:

const foo = jest.fn(x => x);
那么,这是不可靠的:

if (cachedValue[arg]) {
如果
foo
返回
0
,该怎么办?或
?还是
null
?或
未定义
?(事实上,模拟函数也是如此。)

相反,使用

if (Object.prototype.hasOwnProperty.call(cachedValue, arg)) {
但正如@NinaScholz所说:只有在arg可以被合理地强制为字符串而不会丢失信息/导致错误匹配的情况下,它才有效。映射是一个更好的选择,当
arg
是一个对象时,使用弱映射会更好

为了它的价值:

function cacheFunction(foo) {
  const cachedValuesByPrimitive = new Map();
  const cachedValuesByObject = new WeakMap();
  return (arg) => {
    const cache = typeof arg === "object" && arg !== null
        ? cachedValuesByObject
        : cachedValuesByPrimitive;
    if (cache.has(arg)) {
      return cache.get(arg);
    }
    const result = foo(arg);
    cache.set(arg, result);
    return result;
  };
}

export { cacheFunction };
实例:

函数缓存函数(foo){
const cachedValuesByPrimitive=新映射();
const cachedValuesByObject=new WeakMap();
返回值(arg)=>{
常量缓存=typeof arg==“对象”&&arg!==null
?cachedValuesByObject
:cachedValuesByPrimitive;
if(cache.has(arg)){
返回cache.get(arg);
}
const result=foo(arg);
cache.set(参数,结果);
返回结果;
};
}
函数foo(x){
log(“foo调用”,x);
返回x;
}
const cachingFoo=缓存函数(foo);
cachingFoo(真);
cachingFoo(真);
cachingFoo(真);
cachingFoo(真);
仙人掌(10);
仙人掌(10);
仙人掌(10);
仙人掌(10);
常量obj1={a:1};
cachingFoo(obj1);
cachingFoo(obj1);
常量obj2={a:2};
cachingFoo(obj2);
cachingFoo(obj2);

cachingFoo(obj2)您的模拟函数错误
jest.fn
不带参数,只提供一个模拟函数,返回
未定义的
。您需要一个基于收到的参数返回某些内容的函数。也许:

const foo = jest.fn(x => x);
那么,这是不可靠的:

if (cachedValue[arg]) {
如果
foo
返回
0
,该怎么办?或
?还是
null
?或
未定义
?(事实上,模拟函数也是如此。)

相反,使用

if (Object.prototype.hasOwnProperty.call(cachedValue, arg)) {
但正如@NinaScholz所说:只有在arg可以被合理地强制为字符串而不会丢失信息/导致错误匹配的情况下,它才有效。映射是一个更好的选择,当
arg
是一个对象时,使用弱映射会更好

为了它的价值:

function cacheFunction(foo) {
  const cachedValuesByPrimitive = new Map();
  const cachedValuesByObject = new WeakMap();
  return (arg) => {
    const cache = typeof arg === "object" && arg !== null
        ? cachedValuesByObject
        : cachedValuesByPrimitive;
    if (cache.has(arg)) {
      return cache.get(arg);
    }
    const result = foo(arg);
    cache.set(arg, result);
    return result;
  };
}

export { cacheFunction };
实例:

函数缓存函数(foo){
const cachedValuesByPrimitive=新映射();
const cachedValuesByObject=new WeakMap();
返回值(arg)=>{
常量缓存=typeof arg==“对象”&&arg!==null
?cachedValuesByObject
:cachedValuesByPrimitive;
if(cache.has(arg)){
返回cache.get(arg);
}
const result=foo(arg);
cache.set(参数,结果);
返回结果;
};
}
函数foo(x){
log(“foo调用”,x);
返回x;
}
const cachingFoo=缓存函数(foo);
cachingFoo(真);
cachingFoo(真);
cachingFoo(真);
cachingFoo(真);
仙人掌(10);
仙人掌(10);
仙人掌(10);
仙人掌(10);
常量obj1={a:1};
cachingFoo(obj1);
cachingFoo(obj1);
常量obj2={a:2};
cachingFoo(obj2);
cachingFoo(obj2);

cachingFoo(obj2)对我来说,它起作用了。除此之外,我将使用对象而不是数组,或者最好使用
映射,这是类型保存。
如果(cachedValue[arg]){
是危险的。如果
foo
返回
0
,或者
,或者
null
,则使用
if(object.prototype.hasOwnProperty.call(cachedValue,arg)){
但正如@NinaScholz所说:只有当
arg
可以被合理地强制为字符串而不会丢失信息/导致错误匹配时,它才会起作用。
Map
才是更好的选择。
WeakMap
可能更好。你可能想试试lodash的函数,它可以为你做到这一点。@T.J.Crowder,只适用于对象as键。@NinaScholz-很可能是
Map
(对于非对象)和
WeakMap
(对于对象)的组合将是最好的。对我来说,它起作用了。除此之外,我将使用对象而不是数组,或者更好地使用
Map
,这是类型保存。
if(cachedValue[arg]){
是危险的。如果
foo
返回
0
?或
”或
null
,请使用
if(Object.prototype.hasOwnProperty.call(cachedValue,arg)){
但正如@NinaScholz所说:只有当
arg
可以被合理地强制为字符串而不会丢失信息/导致错误匹配时,它才会起作用。
Map
才是一个更好的选择。
WeakMap
可能更好。您可能需要尝试lodash的函数,它可以为您实现这一点。@T.J.Cro