将参数记忆为键
memoize arguments as keys
_.memoize = function(func) {
var cached = {};
return function() {
var args = Array.prototype.slice.call(arguments);
if (cached[args]) {
console.log('returning cached');
return cached[args];
} else {
cached[args] = func.apply(this, args);
return cached[args];
}
};
};
_.memoize = function(func) {
var cached = {};
return function() {
if (cached[arguments]) {
console.log('returning cached');
return cached[arguments];
} else {
cached[arguments] = func.apply(this, arguments);
return cached[arguments];
}
};
};
var add = function(a, b) {
return a + b;
};
var memoAdd = _.memoize(add);
memoAdd(1, 2) => 3;
memoAdd(3, 4)
'returning cached'
=> 3; ????
为什么第二个 memoize 实现在没有 Array.prototype.slice.call 的情况下无法工作?
括号符号实际上是将单词参数字符串化为键而不是实际的实参数吗?
is the bracket notation actually stringifying the word arguments as a key instead of the actual real arguments?
接近,但不完全是。你是对的,涉及字符串化的差异。 arguments
,你可能知道也可能不知道,它不是一个数组,它是一个特殊的Arguments object。由于一些原因,这很不方便,但可以这样说明与此处相关的原因:
function argsObj() {
var obj = {};
var args = Array.prototype.slice.call(arguments);
obj[arguments] = 1;
obj[args] = 2;
return obj;
}
console.log(argsObj(123, 456, 789));
// => { "[object Arguments]": 1,
// "123,456,789": 2
// }
当 Arguments 对象 "stringified" 用作 属性 名称时,我们总是得到 [object Arguments]
。如果我们希望 属性 名称实际反映参数本身——我们需要记忆——我们必须首先将 Arguments 对象转换为数组,这就是 Array.prototype.slice.call(arguments)
所做的。
P.S。即使 Array.prototype.slice
这个记忆方案也有很大的弱点。看看当您尝试使用对象甚至数组作为参数时会发生什么。
arguments 是一个 对象 而不是 数组 。
The arguments object is not an Array. It is similar to an Array, but does not have any Array properties except length.
因此,当您使用第二个实现 运行 记忆时,您会在 cached
变量中看到:
Cached = {} //Empty cache
(index):56 Arguments = [object Arguments] //Arguments is an object
(index):57 Is Array = false //Not an array
(index):74 3
//Will set the object as key, not an array
(index):55 Cached = {"[object Arguments]":3}
(index):56 Arguments = [object Arguments]
(index):57 Is Array = false
//because it will still access to cached[[object ...]]
(index):59 returning cached
(index):76 3
因此它将始终设置和访问密钥 [object Arguments]
,因为 stringification
。
因此,您必须使用第一个实现,使用 Array.prototype.slice.call 将转换为真正的数组。
然后,在字符串化之后你会得到:
Cached = {}
(index):39 Arguments = 1,2 //Is an array as you can see
(index):40 Is Array = true
(index):74 3
//Set an array as key
(index):38 Cached = {"1,2":3}
//Key 3,4 is not in the cached variable, you can continue
(index):39 Arguments = 3,4
(index):40 Is Array = true
(index):76 7
_.memoize = function(func) {
var cached = {};
return function() {
var args = Array.prototype.slice.call(arguments);
if (cached[args]) {
console.log('returning cached');
return cached[args];
} else {
cached[args] = func.apply(this, args);
return cached[args];
}
};
};
_.memoize = function(func) {
var cached = {};
return function() {
if (cached[arguments]) {
console.log('returning cached');
return cached[arguments];
} else {
cached[arguments] = func.apply(this, arguments);
return cached[arguments];
}
};
};
var add = function(a, b) {
return a + b;
};
var memoAdd = _.memoize(add);
memoAdd(1, 2) => 3;
memoAdd(3, 4)
'returning cached'
=> 3; ????
为什么第二个 memoize 实现在没有 Array.prototype.slice.call 的情况下无法工作?
括号符号实际上是将单词参数字符串化为键而不是实际的实参数吗?
is the bracket notation actually stringifying the word arguments as a key instead of the actual real arguments?
接近,但不完全是。你是对的,涉及字符串化的差异。 arguments
,你可能知道也可能不知道,它不是一个数组,它是一个特殊的Arguments object。由于一些原因,这很不方便,但可以这样说明与此处相关的原因:
function argsObj() {
var obj = {};
var args = Array.prototype.slice.call(arguments);
obj[arguments] = 1;
obj[args] = 2;
return obj;
}
console.log(argsObj(123, 456, 789));
// => { "[object Arguments]": 1,
// "123,456,789": 2
// }
当 Arguments 对象 "stringified" 用作 属性 名称时,我们总是得到 [object Arguments]
。如果我们希望 属性 名称实际反映参数本身——我们需要记忆——我们必须首先将 Arguments 对象转换为数组,这就是 Array.prototype.slice.call(arguments)
所做的。
P.S。即使 Array.prototype.slice
这个记忆方案也有很大的弱点。看看当您尝试使用对象甚至数组作为参数时会发生什么。
arguments 是一个 对象 而不是 数组 。
The arguments object is not an Array. It is similar to an Array, but does not have any Array properties except length.
因此,当您使用第二个实现 运行 记忆时,您会在 cached
变量中看到:
Cached = {} //Empty cache
(index):56 Arguments = [object Arguments] //Arguments is an object
(index):57 Is Array = false //Not an array
(index):74 3
//Will set the object as key, not an array
(index):55 Cached = {"[object Arguments]":3}
(index):56 Arguments = [object Arguments]
(index):57 Is Array = false
//because it will still access to cached[[object ...]]
(index):59 returning cached
(index):76 3
因此它将始终设置和访问密钥 [object Arguments]
,因为 stringification
。
因此,您必须使用第一个实现,使用 Array.prototype.slice.call 将转换为真正的数组。
然后,在字符串化之后你会得到:
Cached = {}
(index):39 Arguments = 1,2 //Is an array as you can see
(index):40 Is Array = true
(index):74 3
//Set an array as key
(index):38 Cached = {"1,2":3}
//Key 3,4 is not in the cached variable, you can continue
(index):39 Arguments = 3,4
(index):40 Is Array = true
(index):76 7