0

Я прохожу через «Javascript: окончательное руководство» Дэвида Фланагана.Почему функция memoize в «JS: Окончательное руководство» Д. Фланагана нужна аргументы.length?

В пункте 8.8.4 он показывает функцию высшего порядка, memoize(), который принимает функцию в качестве аргумента и возвращает memoized версии функции:

//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.length с Array.prototype.join.call(arguments, ",") вместо преобразования массива аргументов в строку?

+0

потому что он используется позже для доступа к кешу вызовов. И есть разница, если вы вызываете метод с различным количеством параметров. –

ответ

4

Потому что в противном случае это два вызова будут сохранены с тем же ключом:

memoizedFunc('', ''); 
memoizedFunc(','); 

В обоих случаях вступающих аргументы результаты с одной и той же строки: ,

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])

Обратите внимание, что он сравнивает аргументы с помощью === оператора, например, если вы вызываете функцию дважды с массивами, содержащих то же значение, что бы не вернуться кешированный результат. Вы можете изменить это поведение, глубоко перебирая аргументы и проверяя, совпадают ли все свойства.

+1

Или вы можете использовать Map() для хранения сложных значений в виде ключей: https://github.com/thinkloop/memoizerific – Baz