我正在阅读David Flanagan的“Javascript:The Definitive Guide”。
在第8.8.4段中,他展示了一个高阶函数memoize()
,它接受一个函数作为其参数,并返回该函数的记忆版本:
//Return a memoized version of f.
// It only works if arguments to f all have distinct string representations.
function memoize(f) {
var cache = {}; // Value cache stored in the closure.
return function() {
// Create a string version of the arguments to use as a cache key.
var key = arguments.length + Array.prototype.join.call(arguments,",");
if (key in cache) return cache[key];
else return cache[key] = f.apply(this, arguments);
}
}
在解释中有:“返回的函数将其arguments数组转换为字符串”。
如果我们只需要参数,为什么他将arguments.length
与Array.prototype.join.call(arguments, ",")
连接起来而不是仅将arguments数组转换为字符串?
答案 0 :(得分:4)
因为否则这两个调用将使用相同的密钥存储:
memoizedFunc('', '');
memoizedFunc(',');
在两种情况下,使用相同的字符串连接参数结果:,
答案 1 :(得分:1)
这个功能坏了。即使所有参数都是字符串,它也不起作用。见这个例子:
//Return a memoized version of f.
// It only works if arguments to f all have distinct string representations.
function memoize(f) {
var cache = {}; // Value cache stored in the closure.
return function() {
// Create a string version of the arguments to use as a cache key.
var key = arguments.length + Array.prototype.join.call(arguments,",");
if (key in cache) return cache[key];
else return cache[key] = f.apply(this, arguments);
}
}
const f = memoize(function(...args) {
console.log('f was called')
return args
})
console.log(f(',', ''))
console.log(f('', ','))

第二次使用不同的参数调用函数时,它不应该返回返回缓存的值。但是,'f was called'
只会记录一次,因此无法按预期工作。
要创建一个适用于所有情况的函数,您必须将所有参数存储在缓存中,并迭代它们以检查它们是否相同。它可以这样实现:
const memoize = function(f) {
const cache = []
return (...args) => {
for (const element of cache) {
let hasSameArguments = true
for (const i of args.keys()) {
if (args[i] !== element.args[i]) {
hasSameArguments = false
break
}
}
if (hasSameArguments) {
return element.value
}
}
const value = f(...args)
cache.push({value, args})
return value
}
}
const f = memoize(function(...args) {
console.log('f was called')
return args
})
console.log(f(',', ''))
console.log(f('', ',')) // different arguments, f is called again
console.log(f(true))
console.log(f(true)) // from cache
const someObj = {}
,otherObj = {}
console.log(f(someObj))
console.log(f(someObj)) // the same object, result from cache
console.log(f(otherObj)) // different object, f is called again
console.log(f(otherObj))
console.log(f([1, 2, 3]))
console.log(f([1, 2, 3])) // different object, f is called again
// (because [1, 2, 3] !== [1, 2, 3])

请注意,它使用===
运算符比较参数,因此,例如,如果使用包含相同值的数组调用该函数两次,则不会返回缓存的结果。您可以通过深度迭代参数并检查所有属性是否相同来更改此行为。