С циклом for, почему forEach?

внешний интерфейс JavaScript
С циклом for, почему forEach?

Столько циклов в js,for for...in for...of forEach, некоторые циклы кажутся похожимиforпетля иforEachразница.
Мы обсуждаем с нескольких сторон:

  1. forпетля иforEachсущественная разница.
  2. forпетля иforEachграмматические различия.
  3. forпетля иforEachразница в производительности.

Существенная разница

forЦикл — это циклический метод, который существовал, когда был предложен js.forEachОн предложен ES5 и монтируется на прототипе итерируемых объектов, таких какArray Set Map.
forEach是一个迭代器,负责遍历可迭代对象。 Тактраверс,повторять,повторяемый объектКакие соответственно.
траверс: Относится к каждому члену структуры данных и поведению регулярно при первом посещении.
повторять: итерация — это особая форма рекурсии, метод, предоставляемый итераторами, по умолчанию в определенном порядке.по одномуДоступ к членам структуры данных. Итерация также является поведением обхода.
повторяемый объект: введено в ES6iterableТипы,Array Set Map String arguments NodeListпринадлежатьiterable, они имеют характеристику[Symbol.iterator]метод, объект, содержащий его, считается итерируемымiterable.

未标题-2.png

Узнав этиforEachПо сути, это итератор, связанный сforСущественная разница между циклами заключается в том, чтоforEachотвечает за обход(Array Set Map) итерируемых объектов, аforЦикл — это циклический механизм, который просто проходит через массив.
Давайте поговорим о том, что естьитератор, помните ранее упомянутоеГенератор генераторКогда он вызывается, генерирует объект iTerator (объект iTerator), он имеет.next()метод, который возвращает объект за вызов{value:value,done:Boolean},valueто, что возвращаетсяyieldПосле возвращаемого значения, когдаyieldконец,doneсталиtrue, вызывая и выполняя последовательные итерации для доступа к внутреннему значению.
итераторявляется особым объектом. В спецификации ES6 его флаг должен возвращать объектnext()метод, итеративное поведение оценивается вdoneсреди. Итераторы реализуют обход без раскрытия внутреннего представления. см. код

let arr = [1, 2, 3, 4]  // 可迭代对象
let iterator = arr[Symbol.iterator]()  // 调用 Symbol.iterator 后生成了迭代器对象
console.log(iterator.next()); // {value: 1, done: false}  访问迭代器对象的next方法
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: 4, done: false}
console.log(iterator.next()); // {value: undefined, done: true}

Мы видели это. Пока это итерируемый объект, вызовите внутреннийSymbol.iteratorпредоставит итератор и вернет в соответствии с итераторомnextметод доступа к внутренностям, который такжеfor...ofпринцип реализации.

let arr = [1, 2, 3, 4]
for (const item of arr) {
    console.log(item); // 1 2 3 4 
}

Звонокnextметод возвращает объектvalueзначение и хранится вitemв, покаdoneдляtrueВырваться из цикла, доступны все итерируемые объектыfor...ofПотребление. Давайте посмотрим на другие итерируемые объекты:

function num(params) {
    console.log(arguments); // Arguments(6) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    let iterator = arguments[Symbol.iterator]()
    console.log(iterator.next()); // {value: 1, done: false}
    console.log(iterator.next()); // {value: 2, done: false}
    console.log(iterator.next()); // {value: 3, done: false}
    console.log(iterator.next()); // {value: 4, done: false}
    console.log(iterator.next()); // {value: undefined, done: true}
}
num(1, 2, 3, 4)

let set = new Set('1234')
set.forEach(item => {
    console.log(item); // 1 2 3 4
})
let iterator = set[Symbol.iterator]()
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: 4, done: false}
console.log(iterator.next()); // {value: undefined, done: true}

Таким образом, мы также можем интуитивно видеть итерируемые объекты вSymbol.iteratorИтераторы могут генерироваться при вызове свойств, иforEachОн также генерирует итератор, передавая значение каждого элемента во внутреннюю функцию обратного вызова.
(Заинтересованные студенты могут искатьforEachисходный код,Array Set Mapустановлен на экземпляреforEach, но большинство ответов в Интернете можно получить черезlengthСудя по длине, используяforРеализован петлевой механизм. но вSet MapЕго использование сообщит об ошибке, поэтому я думаю, что это итератор вызова, который продолжает вызыватьnext, который передается в функцию обратного вызова. Так как я не нашел ответ в сети, я не могу делать никаких утверждений.Те, у кого есть ответ, могут оставить мне сообщение в области комментариев)

forпетля иforEachграмматические различия

Зная существенную разницу, в чем грамматическая разница между ними в процессе подачи заявки?

  1. forEachпараметр.
  2. forEachпрерывание.
  3. forEachУдалить собственный элемент, индекс не может быть сброшен.
  4. forЦиклы могут контролировать начальную точку цикла.

forEachпараметры

мы действительно понимаемforEachполный справочный контент? Это выглядит так:

arr.forEach((self,index,arr) =>{},this)

себя:Элементы, пройденные в данный момент в массиве По умолчанию элементы массива получаются в порядке слева направо.
показатель:Индекс текущего элемента массива, индекс первого элемента равен 0 и так далее.
прибытие:Текущий пройденный массив.
это:Это указывает на функцию обратного вызова.

let arr = [1, 2, 3, 4];
let person = {
    name: '技术直男星辰'
};
arr.forEach(function (self, index, arr) {
    console.log(`当前元素为${self}索引为${index},属于数组${arr}`);
    console.log(this.name+='真帅');
}, person)

мы можем использоватьarrРеализовать дедупликацию массива:

let arr1 = [1, 2, 1, 3, 1];
let arr2 = [];
arr1.forEach(function (self, index, arr) {
    arr1.indexOf(self) === index ? arr2.push(self) : null;
});
console.log(arr2);   // [1,2,3]

image.png

forEachпрерывание

в js естьbreak return continueЧтобы прервать или выйти из функции, мы находимся вforЦикл будет использоваться в некоторых нарушениях поведения, ищите оптимизацию обхода массива, это хорошо, но посколькуforEachЭто итератор, и его можно пройти только по порядку, поэтому описанное выше поведение прерывания не поддерживается.

let arr = [1, 2, 3, 4],
    i = 0,
    length = arr.length;
for (; i < length; i++) {
    console.log(arr[i]); //1,2
    if (arr[i] === 2) {
        break;
    };
};

arr.forEach((self,index) => {
    console.log(self);
    if (self === 2) {
        break; //报错
    };
});

arr.forEach((self,index) => {
    console.log(self);
    if (self === 2) {
        continue; //报错
    };
});

если я долженforEachКак насчет того, чтобы выпрыгнуть из петли? На самом деле есть способ,try/catch:

try {
    var arr = [1, 2, 3, 4];
    arr.forEach(function (item, index) {
        //跳出条件
        if (item === 3) {
            throw new Error("LoopTerminates");
        }
        //do something
        console.log(item);
    });
} catch (e) {
    if (e.message !== "LoopTerminates") throw e;
};

Если вы столкнетесьreturnОн не сообщит об ошибке, но не вступит в силу

let arr = [1, 2, 3, 4];

function find(array, num) {
    array.forEach((self, index) => {
        if (self === num) {
            return index;
        };
    });
};
let index = find(arr, 2);// undefined

forEachУдалить собственный элемент, индекс не может быть сброшен

существуетforEachу нас нет контроляindexЗначение , оно будет бездумно увеличиваться только до тех пор, пока не превысит размер массива.lengthВырваться из петли. Так что он не может удалить себяindexСброс, давайте рассмотрим простой пример:

let arr = [1,2,3,4]
arr.forEach((item, index) => {
    console.log(item); // 1 2 3 4
    index++;
});

indexОн не изменяется при добавлении или удалении из тела функции. В реальной разработке очень часто приходится перемещаться по массиву при удалении элемента.forEachБудьте осторожны при удалении.

forЦиклы могут контролировать начальную точку цикла

как указано вышеforEachНачальная точка цикла может быть только 0 без вмешательства человека, иforЦикл отличается:

let arr = [1, 2, 3, 4],
    i = 1,
    length = arr.length;

for (; i < length; i++) {
    console.log(arr[i]) // 2 3 4
};

Предыдущая операция обхода массива и удаления размножения может быть записана как

let arr = [1, 2, 1],
    i = 0,
    length = arr.length;

for (; i < length; i++) {
    // 删除数组中所有的1
    if (arr[i] === 1) {
        arr.splice(i, 1);
        //重置i,否则i会跳一位
        i--;
    };
};
console.log(arr); // [2]
//等价于
var arr1 = arr.filter(index => index !== 1);
console.log(arr1) // [2]

forпетля иforEachразница в производительности

Что касается сравнения производительности, мы добавляемmapитератор, который аналогиченfilterТо же самое для создания нового массива. мы сравниваемfor forEach mapКак выглядит производительность в среде браузера:
Сравнение производительности: for > forEach > карта
В Chrome 62 и Node.js v9.1.0:forкоэффициент циклаforEachв 1 раз быстрее,forEachСравниватьmapОколо 20% быстрее.Анализ причин
for: Цикл for не имеет дополнительного стека вызовов функций и контекста, поэтому его реализация наиболее проста.
forEach: Для forEach сигнатура его функции содержит параметры и контекст, поэтому производительность будет ниже, чем уforцикл.
map:mapСамая медленная причина в том, чтоmapБудет возвращен новый массив, а создание и назначение массива приведет к выделению пространства памяти, что приведет к большим потерям производительности. еслиmapВложенный в цикл, он приведет к большему ненужному потреблению памяти.
Когда вы используете итератор для обхода массива, если вам не нужно возвращать новый массив, а использоватьmapЭто противоречит первоначальному замыслу дизайна. В моей разработке интерфейса я видел, как многие люди просто использовали его для обхода массива.mapиз:

let data = [];
let data2 = [1,2,3];
data2.map(item=>data.push(item));

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


Если эта статья полезна или поучительна для вас, я очень рад