Как использовать переменную подъем с выражением функции в Javascript? - PullRequest
1 голос
/ 12 апреля 2020

Я понимаю, что перемещение переменных - это поведение перемещения объявления в начало функции или глобального контекста. Это показано в приведенном ниже коде:

console.log(a);
var a = 'Hello World!';

Приведенный выше код на самом деле имеет следующее поведение:

var a;
console.log(a);
a = 'Hello World!';

В результате вы получите приведенный выше код: undefined.

В приведенном выше примере важно отметить, что перемещение переменной перемещает только часть объявления вверху. Часть инициализации не перемещается вверх.

Когда я пытаюсь повторить то же поведение, используя выражение функции, я получаю неожиданный вывод.

Это показано в коде ниже:

function sayHello() {
    var say = function() { console.log(hello); }
    var hello= 'Hello World !!';
    return say;
}
sayHello()(); // output Hello World !!

Я пытаюсь понять, почему мы не получили undefined в качестве вывода, поскольку переменная hello инициализируется только после ее использования (аналогично предыдущему примеру).

1 Ответ

3 голосов
/ 12 апреля 2020

Поведение, которое вы видите, происходит от того, как работают замыкания. Дело не в том, что значение hello каким-то образом поднимается, а в том, что код, который читает значение hello (часть console.log(hello)), выполняется только после того, как вы установите значение!

Чтобы не получить перепутать здесь с подъемом, так как это на самом деле не имеет отношения к тому, что вы видите, давайте выпишем код так, как он будет выглядеть после подъема:

function sayHello() {
    var hello;
    var say = function() { console.log(hello); }
    hello = 'Hello World !!';
    return say;
}
sayHello()(); // output Hello World !!

Если вы вставите say() перед строка hello = 'Hello World !!'; будет печатать undefined.

Теперь, когда у вас есть такой код ...

    var hello;
    var say = function() { console.log(hello); }

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

Я пытаюсь понять, почему мы не получили undefined в качестве вывода, потому что переменная hello инициализируется только после ее использования (аналогично предыдущему примеру).

Я думаю, что это ваше недоразумение. Используется, когда вы вызываете функцию say в самом конце - в хронологическом порядке. Тот факт, что взгляд на код сверху вниз hello кажется «использованным» ранее, не имеет значения, потому что это не тот порядок, в котором выполняется код. В строке var say = function () { console.log(hello); } вы просто делаете var say = something;, something не имеет никакого значения в этой точке (это просто должно быть синтаксически правильным). Доступ к hello происходит только при вызове say в конце.

(Вы также можете попробовать что-то вроде var say = function () { derp(); }, и вы заметите, что получаете только ошибку derp is not defined когда вы вызываете эту функцию, а не когда вы ее определяете.)

Итак, в хронологическом порядке происходит следующее:

  • sayHello называется
  • hello создан и содержит undefined
  • say создан и ему назначено выражение функции с телом console.log(hello)
  • hello назначено "Hello World !!"
  • sayHello возвращает say
  • Выражение функции (которое было say) называется
  • console.log(hello) выполняется
    • Помните, что hello содержит "Hello World !!" в эта точка
  • Будет напечатана строка "Hello World !!"

Вы можете расширить этот пример, чтобы лучше понять:

function sayHello() {
  var hello;
  var say = function() { console.log(hello); }  
  hello = 'Hello World !!';
  var think = function() { hello = 'What should I think about?'; }
  return [say, think];
}

var [say, think] = sayHello();
say(); // Prints "Hello World !!";
think();
say(); // prints "What should I think about?"

Как Вы можете видеть, что hello просто живет и может использоваться как say, так и think, даже после возврата sayHello, все эти части кода ссылаются на одну и ту же hello varia. BLE.

...