我正在努力学习一本书中的js memoization示例,这是代码:
Function.prototype.memoized = function(key){
this._values = this._values || {};
return this._values[key] !== undefined ? this._values[key] : this._values[key] = this.apply(this, arguments);
}
这是一个带有完整示例的fiddle
我真正得到的是这段代码是如何工作的以及它的作用,特别是apply
部分:
return this._values[key] !== undefined ? this._values[key] : this._values[key] = this.apply(this, arguments);
我知道并理解apply
如何运作
apply()方法调用一个给定此值的函数,并以数组
的形式提供参数
假设this._values[key]
等于undefined
,则返回的值为this.apply(this, arguments)
:此代码是否会重新启动memoized
函数?我试图在函数中添加一些日志来查看调用函数的次数,但它似乎只启动了一次..
任何人都可以给我一个提示吗?这可能是一个虚假的问题,请耐心等待,谢谢
答案 0 :(得分:2)
让我们使用一个简单的例子,斐波那契数字。
function fib(n) {
if (n < 2) return 1;
return fib.memoized(n-1) + fib.memoized(n-2);
}
在这里,我们可以看到memoized
方法应用于fib
函数,即您的this
keyword引用了fib
函数。它不会重新启动memoized
函数,而是“启动”调用它的函数。但是,它确实将this
设置为函数本身,这没有任何意义。更好:
Function.prototype.memoize = function(key){
if (!this._values)
this._values = {};
if (key in this._values)
return this._values[key];
else
return this._values[key] = this.apply(null, arguments);
// pass null here: ^^^^
}
如果memoized
会返回一个闭包,那就更好了:
Function.prototype.memoized = function(v) {
var fn = this, // the function on which "memoized" was called
values = v || {};
return function(key) {
if (key in values)
return values[key];
else
return values[key] = fn.apply(this, arguments);
}
}
var fib = function(n) {
if (n < 2) return 1;
return fib(n-1) + fib(n-2);
}.memoized();
// or even
var fib = function(n) { return fib(n-1) + fib(n-2) }.memoized({0:1, 1:1});
答案 1 :(得分:1)
备注强>
由于您将memoized
附加到Function.prototype
,因此您只能在其他某个功能上调用此memoized
。就像在你的例子中一样
isPrime.memoized(5)
由于您在函数上调用memoized
,this
将引用调用memoized
的函数。因此,在这种情况下,this
引用isPrime
。
实际解释
this._values = this._values || {};
这一行确保isPrime
有一个名为_values
的属性,并且它应该有一个空对象(如果它不存在)。
this._values[key] !== undefined
此检查是为了确保我们已经使用key
调用了我们。如果值不是undefined
,则返回this._values[key]
。
否则,
this._values[key] = this.apply(this, arguments)
在this.apply(this, arguments)
中存储调用this._values[key]
的结果并将其返回。现在是重要的一部分。
this.apply(this, arguments)
直截了当。 arguments
是一个类似于对象的数组。所以,如果您实际上已经isPrime
实际调用isPrime(1, 2, 3, 4)
,则参数将为{'0': 1, '1': 2, '2': 3, '3': 4}
。现在我们在memoized
内,我们需要调用isPrime
,因为它打算被调用。所以,this.apply(this, arguments)
完成了。 Function.prototype.apply
,尝试在调用函数时传播数组,就像传递给第二个参数的对象一样。