Javascript 循环和迭代

ChongTuWang
• 阅读 959

循环

在Javascript中数组循环使用for循环,跟其他的语言非常类似。

//数组循环
var array = [1,2,3,4,5];
for(var i = 0; i < array.length; i++){
    console.log(array[i]);
}

//对象循环
var obj = {a:1,b:2,c:3};
for(var i in obj){
    console.log(i+':'+obj[i]);
}

迭代

在ES5中新增了几种迭代方法(forEach, every, filter, map, some)。根据文档显示,这些方法都含有两个参数:

callback

    为数组中每个元素执行的函数,该函数接收三个参数:

    currentValue(当前值)

        数组中正在处理的当前元素。

    index(索引)

        数组中正在处理的当前元素的索引。

    array

        方法正在操作的数组。

thisArg可选

    可选参数。当执行回调 函数时用作this的值(参考对象)。


forEach

循环遍历数组。forEach 方法按升序为数组中含有效值的每一项执行一次callback 函数,那些已删除(使用delete方法等情况)或者未初始化的项将被跳过(但不包括那些值为 undefined 的项)。

forEach 遍历的范围在第一次调用 callback 前就会确定。调用forEach 后添加到数组中的项不会被 callback 访问到。如果已经存在的值被改变,则传递给 callback 的值是 forEach 遍历到他们那一刻的值。已删除的项不会被遍历到。如果已访问的元素在迭代时被删除了(例如使用 shift()) ,之后的元素将被跳过 。

forEach() 为每个数组元素执行callback函数;不像 map() 或者 reduce() ,它总是返回 undefined 值,并且不可链式调用。典型用例是在一个链的最后执行副作用。

没有办法中止或者跳出 forEach 循环,除了抛出一个异常。如果你需要这样,使用forEach()方法是错误的,你可以用一个简单的循环作为替代。

简单使用

下面的代码会为每一个数组元素输出一行记录:

function logArrayElements(element, index, array) {
    console.log("a[" + index + "] = " + element);
}

// 注意索引2被跳过了,因为在数组的这个位置没有项
[2, 5, ,9].forEach(logArrayElements);

// a[0] = 2
// a[1] = 5
// a[3] = 9

[2, 5,"" ,9].forEach(logArrayElements);
// a[0] = 2
// a[1] = 5
// a[2] = 
// a[3] = 9

[2, 5, undefined ,9].forEach(logArrayElements);
// a[0] = 2
// a[1] = 5
// a[2] = undefined
// a[3] = 9


let xxx;
// undefined

[2, 5, xxx ,9].forEach(logArrayElements);
// a[0] = 2
// a[1] = 5
// a[2] = undefined
// a[3] = 9

使用thisArg

从每个数组中的元素值中更新一个对象的属性:

function Counter() {
    this.sum = 0;
    this.count = 0;
}

Counter.prototype.add = function(array) {
    array.forEach(function(entry) {
        this.sum += entry;
        ++this.count;
    }, this);
    //console.log(this);
};

var obj = new Counter();
obj.add([1, 3, 5, 7]);

obj.count; 
// 4 === (1+1+1+1)
obj.sum;
// 16 === (1+3+5+7)

如果数组在迭代时被修改了,则其他元素会被跳过

下面的例子输出"one", "two", "four"。当到达包含值"two"的项时,整个数组的第一个项被移除了,这导致所有剩下的项上移一个位置。因为元素 "four"现在在数组更前的位置,"three"会被跳过。 forEach()不会在迭代之前创建数组的副本。

var words = ["one", "two", "three", "four"];
words.forEach(function(word) {
  console.log(word);
  if (word === "two") {
    words.shift();
  }
});
// one
// two
// four

every

测试数组中所有元素是否都通过指定函数的测试,若有一项终止并返回false。

every 方法为数组中的每个元素执行一次 callback 函数,直到它找到一个使 callback 返回 false(表示可转换为布尔值 false 的值)的元素。如果发现了一个这样的元素,every 方法将会立即返回 false。否则,callback 为每一个元素返回 true,every 就会返回 true。callback 只会为那些已经被赋值的索引调用。不会为那些被删除或从来没被赋值的索引调用。

every 不会改变原数组。

every 遍历的元素范围在第一次调用 callback 之前就已确定了。在调用 every 之后添加到数组中的元素不会被 callback 访问到。如果数组中存在的元素被更改,则他们传入 callback 的值是 every 访问到他们那一刻的值。那些被删除的元素或从来未被赋值的元素将不会被访问到。

every 和数学中的"所有"类似,当所有的元素都符合条件才返回true。另外,空数组也是返回true。(空数组中所有元素都符合给定的条件,注:因为空数组没有元素)。

检测所有数组元素的大小

检测数组中的所有元素是否都大于 10。

function isBigEnough(element, index, array) {
  return (element >= 10);
}
var passed = [12, 5, 8, 130, 44].every(isBigEnough);
// passed is false
passed = [12, 54, 18, 130, 44].every(isBigEnough);
// passed is true
var a = [1, 2, 3,, 4].every (function(value){
console.log(value)
   return value       
})//1,2,3,4
console.log(a)//true
a = [1, 2, 3, undefined,4].every (function(value){
console.log(value)
   return value       
})//1,2,3,undefind
console.log(a)//false

filter

使用指定的函数测试所有的元素,创建并返回一个包含所有通过测试的元素的新数组。如果没有通过测试则返回空数组。

filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或等价于 true 的值的元素创建一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。

filter 不会改变原数组,它返回过滤后的新数组。

filter 遍历的元素范围在第一次调用 callback 之前就已经确定了。在调用 filter 之后被添加到数组中的元素不会被 filter 遍历到。如果已经存在的元素被改变了,则他们传入 callback 的值是 filter 遍历到它们那一刻的值。被删除或从来未被赋值的元素不会被遍历到。

使用 filter 创建了一个新数组,该数组的元素由原数组中值大于 10 的元素组成。

var a = [1, 2, 3, 7,4].filter(function(value){
   return value > 4      
})
console.log(a)//[7]

function isBigEnough(element) {
  return element >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// filtered is [12, 130, 44]

map

为数组每一项(不包括通过某些方法删除或者未定义的项,值定义为undefined的项除外)执行一个指定函数,返回一个新数组,每个元素都是回调函数的结果。

map 方法会给原数组中的每个元素都按顺序调用一次  callback 函数。callback 每次执行后的返回值(包括 undefined )组合起来形成一个新数组。 callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。

map 不修改调用它的原数组本身(当然可以在 callback 执行时改变原数组)。

使用 map 方法处理数组时,数组元素的范围是在 callback 方法第一次调用之前就已经确定了。在 map 方法执行的过程中:原数组中新增加的元素将不会被 callback 访问到;若已经存在的元素被改变或删除了,则它们的传递到 callback 的值是 map 方法遍历到它们的那一时刻的值;而被删除的元素将不会被访问到。

下面的代码创建了一个新数组,值为原数组中对应数字的平方根:

var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
// roots的值为[1, 2, 3], numbers的值仍为[1, 4, 9]

使用 map 重新格式化数组中的对象

以下代码将一个包含对象的数组用以创建一个包含新重新格式化对象的新数组。

var kvArray = [{key: 1, value: 10}, 
               {key: 2, value: 20}, 
               {key: 3, value: 30}];

var reformattedArray = kvArray.map(function(obj) { 
   var rObj = {};
   rObj[obj.key] = obj.value;
   return rObj;
});

// reformattedArray 数组为: [{1: 10}, {2: 20}, {3: 30}], 

// kvArray 数组未被修改: 
// [{key: 1, value: 10}, 
//  {key: 2, value: 20}, 
//  {key: 3, value: 30}]

some

测试数组中某些元素是否通过指定函数的测试,若有一项终止循环返回true。

some 为数组中的每一个元素执行一次 callback 函数,直到找到一个使得 callback 返回一个“真值”(即可转换为布尔值 true 的值)。如果找到了这样一个值,some 将会立即返回 true。否则,some 返回 false。callback 只会在那些”有值“的索引上被调用,不会在那些被删除或从来未被赋值的索引上调用。

some 被调用时不会改变数组。

some 遍历的元素的范围在第一次调用 callback. 时就已经确定了。在调用 some 后被添加到数组中的值不会被 callback 访问到。如果数组中存在且还未被访问到的元素被 callback改变了,则其传递给 callback 的值是 some 访问到它那一刻的值。

测试数组元素的值

下面的例子检测在数组中是否有元素大于 10。

function isBiggerThan10(element, index, array) {
  return element > 10;
}

[2, 5, 8, 1, 4].some(isBiggerThan10);  // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true

使用箭头函数测试数组元素的值

[2, 5, 8, 1, 4].some(x => x > 10);  // false
[12, 5, 8, 1, 4].some(x => x > 10); // true

判断数组元素中是否存在某个值

var fruits = ['apple', 'banana', 'mango', 'guava'];

function checkAvailability(arr, val) {
  return arr.some(function(arrVal) {
    return val === arrVal;
  });
}

checkAvailability(fruits, 'kela');   // false
checkAvailability(fruits, 'banana'); // true

将任意值转换为布尔类型

var TRUTHY_VALUES = [true, 'true', 1];

function getBoolean(value) {
  'use strict';
   
  if (typeof value === 'string') { 
    value = value.toLowerCase().trim();
  }

  return TRUTHY_VALUES.some(function(t) {
    return t === value;
  });
}

getBoolean(false);   // false
getBoolean('false'); // false
getBoolean(1);       // true
getBoolean('true');  // true
点赞
收藏
评论区
推荐文章
Souleigh ✨ Souleigh ✨
4年前
JavaScript 和 Node.js 中事件循环
1.JavaScript中事件循环可以参考《JavaScript忍者秘籍第二版》第十三章,讲解的很好。JavaScript中事件循环,主要就在理解宏任务和微任务这两种异步任务。宏任务(macrotask):setTimeOut、setInterval、setImmediate、I/O、各种callback、UI渲染、messageCh
blmius blmius
4年前
JS中arr.forEach()如何跳出循环
示例我们都知道for循环里要跳出整个循环是使用break,但在数组中用forEach循环如要退出整个循环呢?使用break会报错,使用return也不能跳出循环。使用break将会报错:vararr使用return也不能跳出整个循环:vararr那么在用forEach()遍历数组时要如何才能跳出循环呢?经过查找资料后,我找到了两种方法可以实现跳出
Stella981 Stella981
4年前
Javascript并发模型和事件循环
JavaScript的"并发模型"是基于事件循环的,这个并发模型有别于Java的多线程,javascript的并发是单线程的。Javascript中有个重要一块,EventLoop,能把单线程的JavaScript使出多线程的感觉。"EventLoop是一个程序结构,用于等待和发送消息和事件。(aprogrammingconst
Wesley13 Wesley13
4年前
Java如何遍历二维数据
/\需求:二维数组遍历外循环控制的是二维数组的长度,其实就是一维数组的个数。内循环控制的是一维数组的长度。\/classArray2Test{publicstaticvoidmain(String\\args){//定义一个二维数组int\\\\arr{{1,2,3}
Stella981 Stella981
4年前
JavaScript 事件循环机制
javascript是一门单线程的非阻塞的脚本语言。单线程意味着javascript在执行代码的任何时候,都只有一个主线程来处理所有的任务。那么javascript引擎是如何实现这一点的呢?因为事件循环(eventloop)。先上图:!event_loop(https://oscimg.oschina.net/oscnet/up6
Stella981 Stella981
4年前
JavaScript遍历循环
定义一个数组和对象constarr'a','b','c','d','e','f';constobj{a:1,b:2,c:3,d:4}for()经常用来遍历数组元素遍历值为数组元素索引f
Wesley13 Wesley13
4年前
Java循环结构
Java循环结构for,while和do...while顺序结构的程序语句只能被执行一次。如果您想要同样的操作执行多次,就需要使用循环结构。while循环do...while循环for循环在Java5中引入了一种主要用于数组的增强
小万哥 小万哥
2年前
Python 循环
Python有两个基本的循环命令:while循环for循环while循环使用while循环,我们可以在条件为真的情况下执行一组语句。示例,打印i,只要i小于6:pythoni1whilei<6:print(i)i1注意:记得增加i的值,否则循环将永远继续
小万哥 小万哥
1年前
NumPy 数组迭代与合并详解
NumPy数组迭代NumPy数组迭代是访问和处理数组元素的重要方法。它允许您逐个或成组地遍历数组元素。基本迭代我们可以使用Python的基本for循环来迭代NumPy数组。一维数组迭代:pythonimportnumpyasnparrnp.array(1
小万哥 小万哥
1年前
Kotlin 控制流和数组操作详解
Kotlin的when表达式提供了一种比if..else更清晰的方式来选择执行多个代码块之一,类似于Java的switch语句但更为强大和灵活。while循环允许在条件为真时重复执行代码块,而do..while循环则保证至少执行一次。break和continue可用于控制循环流程:前者终止循环,后者跳过当前迭代。数组则用于存储多个值,可以创建、访问、修改数组元素及遍历整个数组。这些构造使得编写简洁且高效的代码成为可能。
小万哥 小万哥
1年前
Kotlin 循环与函数详解:高效编程指南
Kotlin中的循环结构让你能轻松遍历数组或范围内的元素。使用for循环结合in操作符,可以简洁地访问数组中的每个项,如字符串数组或整数数组。对于范围,可以用..来定义一系列连续的值并进行迭代。此外,Kotlin支持通过break和continue控制循环流程。函数则允许封装可复用的代码块,你可以定义接受参数并返回值的函数,利用简写语法使代码更加紧凑。例如,myFunction(x:Int,y:Int)xy简洁地定义了一个计算两数之和的函数。