Недавно я смотрю практику ES2015, в нем есть поговорка, в которой говорится
В JavaScript нет возможности на уровне блоков
Вы можете не понять эту проблему, давайте сначала посмотрим на пример
var a = [] for (var i = 0; i <10; i ++) {a [i] = function () {console.log (i); }} a [6] ();Я думаю, что многие думают, что результат этого вопроса - 6, но, к сожалению, ответ - 10. Попробуйте что -то еще. a [7] (), a [8] () и a [8] () все имеют 10 !!
Поскольку JS часто охватывает примитивные переменные в соответствующие объекты при обработке, например, для var str = "hello world"; str.slice (1).
Реальный процесс JS, вероятно, вар STR = "Hello World"; New String (str) .slice (1). Такой процесс может вызвать у нас проблемы с пониманием проблемы.
Чтобы объяснить эту проблему здесь, я принадлежу к типу номера в примитивном типе, я явно объявляю ее типом номера. Поскольку процесс назначения базового типа заключается в повторном применении памяти и изменении направления переменной, мы также используем процесс повторного номера объекта для моделирования этого процесса. Модифицированный код заключается в следующем:
var a = [] var i = новое число (0); for (; i <10; i = новое число (i+1)) {a [i] = function () {console.log (i.toString ()); }} a [6] (); // 10a [7] (); // 10a [8] (); // 10a [9] (); // 10a [9] (); // 10Давайте посмотрим на относительные адреса памяти этих переменных в сочетании с программой.
(function () {var id = 0; function generateId () {return id ++;}; object.prototype.id = function () {var newId = generateId (); this.id = function () {return newId;}; return newId;};}) (); var a = [] var i = new (0); новое число (i+1), i.id ()) {a [i] = function () {console.log (i.id ()); console.log (i.ToString ()); }} a [6] (); // 10 10a [7] (); // 10 10a [8] (); // 10 10a [9] (); // 10 10console.log (i.id ()) // 10Здесь мы действительно смоделировали весь эффект «назначения» нашего I, и относительный адрес, который я изменил с 0 на 10 (в конце концов, его необходимо добавить один раз, прежде чем он сможет выпрыгнуть из цикла).
Глядя на относительный адрес I, мы нашли проблему: когда функция, соответствующая [x] (x: 0 ~ 9), выполняется, относительный адрес, который я ссылается, является 10. Почему?
Здесь мы будем включать проблему с масштабами на уровне блока. Здесь мы цитируем отрывок из Руан Ифенг во введении в ES6:
ES5 имеет только глобальный объем и функциональный объем, но без сфера действия уровня блока.
ES5 является наиболее широко используемой версией JS. В этом предложении говорится, что в JavaScript нет возможности блока. Существует только глобальная масштаба и область на уровне блока.
Как понять? Например
for (var i = 0; i <10; i ++) {console.log (i);} console.log (i); // 10console.log (window.i); // 10Интуитивно, мы думаем, что для цикла является блок кода и должен принадлежать к сфере на уровне блока. Тем не менее, не только может вывозить от 0 до 9 обычно, но также может выводить 10 внешних в цикле. В то же время мы обнаружили, что, хотя мы определили I на цикле для FOR, кажется, что я висят на глобальном окне (если это среда выполнения Nodejs, он будет висеть на глобальном объекте)
Следовательно, блоки, такие как для петли в JavaScript, не будут иметь эффекта прицела на уровне блока. Определение переменных в кодовых блоках, таких как петли, ничем не отличается от непосредственного определения переменных в текущей области.
Но мы можем изолировать область с помощью функций:
(function () {for (var i = 0; i <10; i ++) {console.log (i);} console.log (i);}) () console.log (i); //// не определеноВ то же время, если консоль.log (window.i); выполнено, неопределенный результат будет получен. Здесь мы используем непосредственную функцию выполнения, чтобы сформировать область применения. Это играет роль, похожую на кодовый блок. После этой области функции, переменной, которую я больше не могу получить доступ. Тем не менее, ко мне можно получить доступ в любое время в рамках функции.
Вернитесь к предыдущему вопросу, а затем мы поймем его в сочетании только с глобальным объемом и сферой на уровне блоков в JavaScript. В цикле FO, определение I должно быть определена в текущей области, то есть в области окна. В теле цикла мы назначаем функцию [i]. Когда мы выполняем эту функцию, ситуация заключается в следующем:
Я не существует в функции, поэтому мы следуем цепочке прицелов, чтобы найти i. I мы выводим в это время это я. Поскольку я выпрыгиваю из последнего +1 петли, мне становится 10, поэтому результат вывода всегда 10. Но то, что нам действительно нужно, не последнее I, но я в промежуточном процессе. Если мы хотим решить эту проблему, нам нужно отложить в сторону переменную I (потому что последний я неизбежно становится 10). Нам нужно позволить функции, соответствующей [0], обратиться к значению 0, и позволить функции, соответствующей [1], обратиться к значению 1. Как показано на рисунке ниже:
Вернитесь к нашему предыдущему коду.
Стрелка на рисунке показывает, что мы можем получить доступ к I (0 ~ 9). Здесь, поскольку цикл FOR не образует прицел на уровне блока, мы получаем доступ к определению цикла FO, когда следуем цепочке областей.
Здесь мы завершаем наш код с помощью непосредственной функции выполнения, которая может сформировать область, и мы передаем значение I для него. Следующее:
var a = [] var i = новое число (0); console.log (i.id ()); // 0for (; i <10; i = новое число (i+1), i.id ()) {(function (i) {a [i] = function () {console.log (i.id ()); console.log (i.tostring ()); // 6 6a [7] (); // 7 7a [8] (); // 8 8a [9] (); // 9 9 anconsole.log (i.id ()); // 10}Поскольку эта функция немедленного выполнения относится к числовому значению 0 ~ 9, когда мы выполняем функцию a [i], мы сначала найдем область применения функции немедленного выполнения вдоль цепочки объема. Функция немедленного выполнения поддерживает численную ссылку от 0 ~ 9, и мы можем правильно вывести значение I в функции A [i]. Благодаря результатам выполнения мы видим, что не только результат выполнения является правильным, но и относительный адрес памяти значения, который мы ссылаемся, также является правильным. Затем мы меняем объект номер, который первоначально был явно объявлен для тестирования. Следующее:
var a = []; for (var i = 0; i <10; i ++) {(function (i) {a [i] = function () {console.log (i);}}) (i);}Наконец, давайте посмотрим на синтаксис ES6, рекомендованный с использованием let вместо VAR, а также компиляция и генерирование кода ES5 через Baeble:
// es6 code var a = [] for (let i = 0; i <10; i ++) {a [i] = function () {console.log (i); }} a [6] (); // Вабель скомпилированный и сгенерированный код ES5 "Использовать rest"; var a = []; var _loop = function _loop (i) {a [i] = function () {console.log (i); };}; for (var i = 0; i <10; i ++) {_loop (i);} a [6] ();Посмотрим, очень ли наше решение очень похоже на решение ES6. Здесь наша функция немедленного выполнения эквивалентна выполнению функции _loop и _loop (i) в сгенерированном коде ES5.