Шаблон выражения именованной функции внутри функции - PullRequest
0 голосов
/ 30 марта 2019

Следующий код взят из исходного кода Jest:

function _path() {
  const data = _interopRequireDefault(require('path'));

  _path = function _path() {
    return data;
  };

  return data;
}

Почему у нас есть выражение именованной функции в середине?Как и когда можно использовать этот шаблон?

1 Ответ

6 голосов
/ 30 марта 2019

Внешняя функция называется _path. Затем внутри нее строка _path = function _path() перезаписывает переменную _path (в настоящее время назначенную функции _path) другой функцией, называемой _path.

Таким образом, при выполнении функции перезаписывает самой новой функцией, которая выполняет другую функцию. Вот простая иллюстрация этого принципа:

function f() {
  console.log("outer");
  f = function f() {
    console.log("inner");
  }
}

f(); //outer
f(); //inner
f(); //inner

Итак, это , что делает. Что касается , почему это делает это - кэширование. Нужно только посмотреть / вычислить значение один раз, и тогда каждое другое выполнение будет кэшировано. Итак, вот пример, где lookup - это фиктивный резерв для сетевой операции.

function lookup() {
  console.log("making a network call");
  return 4;
}

function f() {
  var output = lookup();

  f = function f() {
    return output;
  }
  
  return output;
}

console.log(f()); //network call -> 4
console.log(f()); //4
console.log(f()); //4

То же самое можно сделать с тяжелым вычислением, которое не требует сетевого вызова - вместо повторения вычисления и использования циклов ЦП каждый раз, результат может быть вычислен только один раз.

Наконец, почему внутренняя функция называется _path - нет строгой причины называть это так. Код будет работать так же, даже если у него нет имени. Тем не менее, заменяет внешнюю функцию, поэтому сохранение имени - хорошая идея. Это также может помочь в отладке, когда вы видите трассировку стека.

В общем, эта техника называется памятка . Примечание: это правильное написание, нет r . Хотя я сомневаюсь, что кто-нибудь может запутаться, если вы вставите это.

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

function memoize(func) {
  //keep a cache for all results
  const cache = {};
  
  //make a new function
  const memo = function() {
    //get the arguments from the input
    var key = JSON.stringify(...arguments);

    let result;
    if (cache.hasOwnProperty(key)) {
      //get result from cache
      result = cache[key];
    } else {
      //calculate the result and put it in the cache
      result = func(...arguments);
      cache[key] = result;
    }

    return result;
  }
  
  return memo;
}

function lookup(data) {
  console.log("network call");
  return data + 4;
}

function calculate(data) {
  console.log("heavy operation");
  return data + 2;
}

let memLookup = memoize(lookup);
console.log(memLookup(4)); //network call -> 8
console.log(memLookup(4)); //8
console.log(memLookup(6)); //network call -> 10
console.log(memLookup(6)); //10

let memCalculate = memoize(calculate);
console.log(memCalculate(4)); //heavy operation -> 6
console.log(memCalculate(4)); //6
console.log(memCalculate(6)); //heavy operation -> 8
console.log(memCalculate(6)); //8
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...