Si vuelvo a escribir el bucle for, me martillaré

¡Acostúmbrate a escribir juntos! Este es el cuarto día de mi participación en el "Nuevo plan diario de los Nuggets·Desafío de actualización de abril", haz clic para ver los detalles del evento .

Entre los métodos transversales, for ejecuta el más rápido sin ninguna función adicional de pila de llamadas y contexto. Pero en el desarrollo real, tenemos que combinar la semántica, la legibilidad y el rendimiento del programa para elegir qué esquema usar. Echemos un vistazo a los cinco métodos de for , foreach , map , for...in , for...of live battle.

Presentación

por

Soy el primero en atravesar la declaración, y todos aquí deben llamarme abuelo. Puedo satisfacer la gran mayoría de las necesidades de los desarrolladores.

// 遍历数组
let arr = [1,2,3];
for(let i = 0;i < arr.length;i++){
    console.log(i) // 索引,数组下标
    console.log(arr[i]) // 数组下标所对应的元素
}

// 遍历对象
let profile = {name:"April",nickname:"二十七刻",country:"China"};
for(let i = 0, keys=Object.keys(profile); i < keys.length;i++){
    console.log(keys[i]) // 对象的键值
    console.log(profile[keys[i]]) // 对象的键对应的值
}

// 遍历字符串
let str = "abcdef";
for(let i = 0;i < str.length ;i++){
    console.log(i) // 索引 字符串的下标
    console.log(str[i]) // 字符串下标所对应的元素
}

// 遍历DOM 节点
let articleParagraphs = document.querySelectorAll('.article > p');
for(let i = 0;i<articleParagraphs.length;i++){
    articleParagraphs[i].classList.add("paragraph");
    // 给class名为“article”节点下的 p 标签添加一个名为“paragraph” class属性
}
复制代码

para cada

Estoy publicando en versión ES5. La función de devolución de llamada se ejecuta una vez para cada elemento de la matriz con un valor válido en orden ascendente, los elementos eliminados o no inicializados se omiten (por ejemplo, en matrices dispersas). Soy una versión mejorada del bucle for.

// 遍历数组
let arr = [1,2,3];
arr.forEach(i => console.log(i))

// logs 1
// logs 2
// logs 3
// 直接输出了数组的元素

//遍历对象
let profile = {name:"April",nickname:"二十七刻",country:"China"};
let keys = Object.keys(profile);
keys.forEach(i => {
    console.log(i) // 对象的键值
    console.log(profile[i]) // 对象的键对应的值
})
复制代码

mapa

También lancé la versión ES5, puedo crear una nueva matriz, el resultado de la nueva matriz es el valor de retorno de cada elemento en la matriz original después de llamar a la función proporcionada una vez.

let arr = [1,2,3,4,5];
let res = arr.map(i => i * i);

console.log(res) // logs [1, 4, 9, 16, 25]
复制代码

para... la enumeración

Estoy publicando en versión ES5. Recorre las propiedades enumerables de un objeto distintas de Símbolo en cualquier orden.

// 遍历对象
let profile = {name:"April",nickname:"二十七刻",country:"China"};
for(let i in profile){
    let item = profile[i];
    console.log(item) // 对象的键值
    console.log(i) // 对象的键对应的值

// 遍历数组
let arr = ['a','b','c'];
for(let i in arr){
    let item = arr[i];
    console.log(item) // 数组下标所对应的元素
    console.log(i) // 索引,数组下标

// 遍历字符串
let str = "abcd"
for(let i in str){
    let item = str[i];
    console.log(item) // 字符串下标所对应的元素
    console.log(i) // 索引 字符串的下标
}
复制代码

para... de Iteración

Estoy publicando en versión ES6. Cree un ciclo de iteración sobre objetos iterables (incluidos Array, Map, Set, String, TypedArray, objetos de argumentos, etc.), llame a ganchos de iteración personalizados y ejecute declaraciones para los valores de cada propiedad distinta.

// 迭代数组数组
let arr = ['a','b','c'];
for(let item of arr){
    console.log(item)
}
// logs 'a'
// logs 'b'
// logs 'c'

// 迭代字符串
let str = "abc";
for (let value of str) {
    console.log(value);
}
// logs 'a'
// logs 'b'
// logs 'c'

// 迭代map
let iterable = new Map([["a", 1], ["b", 2], ["c", 3]]
for (let entry of iterable) {
    console.log(entry);
}
// logs ["a", 1]
// logs ["b", 2]
// logs ["c", 3]

// 迭代map获取键值
for (let [key, value] of iterable) {
    console.log(key)
    console.log(value);
}


// 迭代set
let iterable = new Set([1, 1, 2, 2, 3, 3,4]);
for (let value of iterable) {
    console.log(value);
}
// logs 1
// logs 2
// logs 3
// logs 4

// 迭代 DOM 节点
let articleParagraphs = document.querySelectorAll('.article > p');
for (let paragraph of articleParagraphs) {
    paragraph.classList.add("paragraph");
    // 给class名为“article”节点下的 p 标签添加一个名为“paragraph” class属性。
}

// 迭代arguments类数组对象
(function() {
  for (let argument of arguments) {
    console.log(argument);
  }
})(1, 2, 3);
// logs:
// 1
// 2
// 3


// 迭代类型数组
let typeArr = new Uint8Array([0x00, 0xff]);
for (let value of typeArr) {
  console.log(value);
}
// logs:
// 0
// 255
复制代码

Después de la primera ronda de autopresentación y presentación de habilidades, aprendimos:

  • La declaración for es la declaración de bucle más primitiva. Defina una variable i (tipo de número, que representa el subíndice de la matriz) y haga un bucle y acumule i de acuerdo con ciertas condiciones. La condición suele ser la duración del objeto de bucle y el bucle se detiene cuando se supera la longitud. Debido a que el objeto no puede determinar la longitud, se usa con Object.keys().
  • forEach ES5 propuesto. Afirmando ser una versión mejorada de la declaración for, se puede encontrar que es mucho más simple de escribir que la declaración for. Pero también es esencialmente un bucle sobre una matriz. forEach ejecuta la función de devolución de llamada una vez por elemento de matriz. Es decir, la matriz en la que se llama, por lo que la matriz original no se modificará. El valor devuelto no está definido.
  • map  ES5 提出。给原数组中的每个元素都按顺序调用一次  callback 函数。生成一个新数组,不修改调用它的原数组本身。返回值是新的数组。
  • for...in  ES5 提出。遍历对象上的可枚举属性,包括原型对象上的属性,且按任意顺序进行遍历,也就是顺序不固定。遍历数组时把数组的下标当作键值,此时的i是个字符串型的。它是为遍历对象属性而构建的,不建议与数组一起使用。
  • for...of ES6 提出。只遍历可迭代对象的数据。

能力甄别

作为一个程序员,仅仅认识他们是远远不够的,在实际开发中鉴别他们各自的优缺点。因地制宜的使用他们,扬长避短。从而提高程序的整体性能才是能力之所在。

关于跳出循环体

在循环中满足一定条件就跳出循环体,或者跳过不符合条件的数据继续循环其它数据。是经常会遇到的需求。常用的语句是break 与 continue。

简单的说一下二者的区别,就当复习好了。

  • break语句是跳出当前循环,并执行当前循环之后的语句;
  • continue语句是终止当前循环,并继续执行下一次循环;

注意:forEach 与map 是不支持跳出循环体的,其它三种方法均支持。

原理 :查看forEach实现原理,就会理解这个问题。

Array.prototype.forEach(callbackfn [,thisArg]{
    
}
复制代码

传入的function是这里的回调函数。在回调函数里面使用break肯定是非法的,因为break只能用于跳出循环,回调函数不是循环体。

在回调函数中使用return,只是将结果返回到上级函数,也就是这个for循环中,并没有结束for循环,所以return也是无效的。

map() 同理。

map()链式调用

map() 方法是可以链式调用的,这意味着它可以方便的结合其它方法一起使用。例如:reduce(), sort(), filter() 等。但是其它方法并不能做到这一点。forEach()的返回值是undefined,所以无法链式调用。

// 将元素乘以本身,再进行求和。
let arr = [1, 2, 3, 4, 5];
let res1 = arr.map(item => item * item).reduce((total, value) => total + value);

console.log(res1) // logs 55 undefined"
复制代码

for...in会遍历出原型对象上的属性

Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
var arr = ['a', 'b', 'c'];
arr.foo = 'hello
for (var i in arr) {
    console.log(i);
}
// logs
// 0
// 1
// 2
// foo
// arrCustom
// objCustom
复制代码

然而在实际的开发中,我们并不需要原型对象上的属性。这种情况下我们可以使用hasOwnProperty() 方法,它会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。如下:

Object.prototype.objCustom = function() {};
Array.prototype.arrCustom = function() {};
var arr = ['a', 'b', 'c'];
arr.foo = 'hello
for (var i in arr) {
    if (arr.hasOwnProperty(i)) {
        console.log(i);
    }
}
// logs
// 0
// 1
// 2
// foo

// 可见数组本身的属性还是无法摆脱。此时建议使用 forEach
复制代码

对于纯对象的遍历,选择for..in枚举更方便;对于数组遍历,如果不需要知道索引for..of迭代更合适,因为还可以中断;如果需要知道索引,则forEach()更合适;对于其他字符串,类数组,类型数组的迭代,for..of更占上风更胜一筹。但是注意低版本浏览器的是配性。

性能

有兴趣的读者可以找一组数据自行测试,文章就直接给出结果了,并做相应的解释。

for > for-of > forEach > map > for-in
复制代码
  • for 循环当然是最简单的,因为它没有任何额外的函数调用栈和上下文;
  • for...of只要具有Iterator接口的数据结构,都可以使用它迭代成员。它直接读取的是键值。
  • forEach,因为它其实比我们想象得要复杂一些,它实际上是array.forEach(function(currentValue, index, arr), thisValue)它不是普通的 for 循环的语法糖,还有诸多参数和上下文需要在执行的时候考虑进来,这里可能拖慢性能;
  • map() 最慢,因为它的返回值是一个等长的全新的数组,数组创建和赋值产生的性能开销很大。
  • for...in需要穷举对象的所有属性,包括自定义的添加的属性也能遍历到。且for...in的key是String类型,有转换过程,开销比较大。

总结

在实际开发中我们要结合语义话、可读性和程序性能,去选择究竟使用哪种方案。

如果你需要将数组按照某种规则映射为另一个数组,就应该用 map。

如果你需要进行简单的遍历,用 forEach 或者 for of。

如果你需要对迭代器进行遍历,用 for of。

如果你需要过滤出符合条件的项,用 filterr。

如果你需要先按照规则映射为新数组,再根据条件过滤,那就用一个 map 加一个 filter。

En resumen, ajustar las medidas a las condiciones locales y cambiar con el tiempo. No ignore la semántica y la legibilidad debido a una búsqueda excesiva del rendimiento. Bajo tu gobierno, los cinco solo pueden jugar con sus propias fuerzas, y nadie quiere dominar.

- Fin -

Supongo que te gusta

Origin juejin.im/post/7085164529658626061
Recomendado
Clasificación