将参数记为键

时间:2015-08-12 23:25:53

标签: javascript closures memoization

_.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; ????

为什么没有Array.prototype.slice.call,第二个memoize实现不起作用?

是括号实际上将字参数字串化为键而不是实际的真实参数吗?

2 个答案:

答案 0 :(得分:1)

  

是括号实际上将字参数字串化为键而不是实际的真实参数吗?

关闭,但不完全。你是否正确,涉及到字符串化的差异。 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对象被“字符串化”以用作属性名称时,我们始终得到[object Arguments]。如果我们希望属性名实际反映参数本身 - 我们需要进行memoization - 我们必须首先将Arguments对象转换为数组,这是Array.prototype.slice.call(arguments)所做的。

P.S。即使使用Array.prototype.slice这个备忘录方案也有很大的弱点。看看当你使用对象甚至数组的参数进行尝试时会发生什么。

答案 1 :(得分:0)

arguments 对象,而不是数组

  

arguments对象不是Array。它类似于Array,但除了length之外没有任何Array属性。

因此,当您使用第二个实现运行memoization时,您会在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