【发布时间】:2022-11-03 20:05:23
【问题描述】:
我目前遇到了 JavaScript 中 memoize 函数的问题。最后 2 次测试未通过。我会更乐意提供帮助。
问题如下:
-
编写一个 memoize 函数,该函数接受一个必需的回调函数和一个可选的解析器函数。 memoize 函数返回回调函数的 memoized 版本,定义如下:
-
memoized 函数的所有返回值都被缓存。如果使用现有缓存键(定义如下)调用 memoized 回调,则返回该缓存值而无需再次调用回调。
-
缓存键是根据可选的解析器函数定义的。如果未提供解析器函数,则缓存键是将记忆函数参数作为数组传递给 JSON.stringify 的结果。如果提供了自定义解析器函数,则应将参数单独传递给该函数,其返回值将是缓存键(请注意,它可以是任何类型)。
-
memoized 函数也应该有三个方法: clear():清除缓存。 delete(...args):如果存在,则删除与传递的参数对应的缓存条目。 has(...args):如果缓存有对应于传递参数的条目,则返回布尔值 true,否则返回 false。为简单起见,您无需担心绑定 this 上下文(即,您可以假设回调不引用 this)。
回调函数如下所示:
const callback = (...args) => args;
这是应该返回的输入和结果
const memoized = memoize(callback);
memoized(123); // calls callback, returns 123
memoized(123); // returns 123
memoized(123, 'abc'); // calls callback, returns [123, 'abc']
const memoized2 = memoize(callback, args => args[0]);
memoized2(123); // calls callback, returns 123
memoized2(123); // returns 123
memoized2(123, 'abc'); // returns 123
memoized('abc', 123); // calls callback, returns ['abc', 123]
memoized2('abc'); // returns ['abc', 123]
我已将所有参数存储在缓存中,当调用相同的参数时,将从缓存中返回结果。
这是我的代码
function memoize(cb) {
const memo = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (!memo.has(args)) {
memo.set(key, cb(...args));
return memo.get(key);
}
return memo.get(key);
};
}
这是测试
const chai = require("chai");
const spies = require("chai-spies");
const { expect } = chai;
chai.use(spies);
const spy = () => chai.spy(() => {});
const { memoize } = require("../memoize.js");
describe("memoize", () => {
it("callback without parameters is never called twice", () => {
const callback = spy(() => {});
const memoized = memoize(callback);
expect(callback).to.have.been.called.exactly(0);
memoized();
expect(callback).to.have.been.called.exactly(1);
memoized();
expect(callback).to.have.been.called.exactly(1);
memoized();
memoized();
expect(callback).to.have.been.called.exactly(1);
});
it("callback with a single parameter is handled properly", () => {
const callback = spy((val) => val * 2);
const memoized = memoize(callback);
expect(callback).to.have.been.called.exactly(0);
const val1 = memoized(1);
expect(callback).to.have.been.called.exactly(1);
expect(val1).to.equal(2);
const val2 = memoized(1);
expect(callback).to.have.been.called.exactly(1);
expect(val2).to.equal(2);
const val3 = memoized(2);
expect(callback).to.have.been.called.exactly(2);
expect(val3).to.equal(4);
const val4 = memoized(2);
expect(callback).to.have.been.called.exactly(2);
expect(val4).to.equal(4);
const val5 = memoized(1);
expect(callback).to.have.been.called.exactly(2);
expect(val5).to.equal(2);
});
it("has function works as expected", () => {
const callback = spy((...args) => args);
const memoized = memoize(callback);
expect(memoized.has()).to.be.false;
expect(memoized.has(123)).to.be.false;
expect(memoized.has(123, "abc")).to.be.false;
memoized();
expect(memoized.has()).to.be.true;
memoized(123);
expect(memoized.has(123)).to.be.true;
memoized(123, "abc");
expect(memoized.has(123, "abc")).to.be.true;
expect(callback).to.have.been.called.exactly(3);
});
});
【问题讨论】:
-
您的
memoize()函数没有可选的解析器 -
if (!memo.has(args))- 两个数组永远不会相同 - 无论它们的内容如何。你必须测试key -
@Andreas 我试图将解析器包含在扩展运算符中。例如 (...cb)。然后我检查 cb[1] 是否存在,如果存在,则解析器用于他的目的。但没有什么不同。测试是我的暗示,关于 fn 应该如何工作。
-
如果你正在做
memo.set(key, cb(...args));和memo.get(key);,那么memo.has(args)肯定应该是memo.has(key),否则代码没有任何意义。
标签: javascript function caching callback memoization