Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaScript 循环遍历 #145

Open
felix-cao opened this issue Feb 15, 2019 · 1 comment
Open

JavaScript 循环遍历 #145

felix-cao opened this issue Feb 15, 2019 · 1 comment

Comments

@felix-cao
Copy link
Owner

felix-cao commented Feb 15, 2019

循环 (loop) 或者叫遍历 (loop through),还有一种说法叫迭代 (Iterate), 是让计算机做重复任务的有效的方法。循环是所有语言最基础的语法,

跳出循环

  • return 语句只能出现在函数体内, 不可用于for(结合 Jquery 中的 $.each去理解);
    • return true, 跳出本次循环
    • return false, 终止循环,JS 事件流中阻止默认时间,如阻止form表单的默认提交行为
  • continue/break 只能用在for语句、或者for/in语句、while语句、do/while语句的循环体;

JavaScript 中的遍历主要是对“集合”的遍历,JavaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又新增了 MapSet 。本文重点讨论 JavaScript 原有数据“集合”的遍历,即 ArrayObject

Array 提供了一种顺序存储一组元素的功能,并可以按索引来访问。
Object 是一个属性和方法的集合,它是无序的,通过属性名或方法名去访问。

JavaScript 的循环遍历语法如下:

命令 数组 对象 Notes
1. for x 通过初始条件结束条件递增条件来循环执行语句块
2. for ...in 把一个对象的所有属性依次循环出来
3. while x 只指定循环条件为 true
4. do ...while x 循环完成时判断循环条件是否进入下一次循环
5. forEach x 调用数组的每个元素,并将元素传递给回调函数
6. for ...of ES6 新增的,用来弥补 forEach 和 for...in 的短板

本文主要介绍前 5 个常见的循环语句,此外ES5 还给我们提供了 map、reduce、filter、some、every
等常见的高阶函数,请移步《JavaScript 高阶函数(Higher-order function) 》, 关于 for ...of,因为是 ES6 中新增的语法,回头会在 ES6 中讲解。

一、for 循环

for 循环,通过 初始条件结束条件递增条件 来循环执行语句块:

var x = 0;
for ( var i=1; i<=100; i++) {
    x = x + i;
}
x; // 5050

让我们来分析一下 for 循环的控制条件: 🔢

  • var i=1 这是初始条件,声明变量 i, 并赋值 1
  • i<=100 这是判断条件,满足时就继续循环,不满足就退出循环;
  • i++ 这是每次循环后的递增条件,由于每次循环后变量 i 都会加 1,因此它终将在若干次循环后不满足判断条件 i<=100 而退出循环。

👍 for 循环不能遍历对象,这是因为 递增条件 决定着循环对象必须是有序的,而 Array 是有序,Object 是无序的。

for 循环最常用的地方是利用索引来遍历数组或类数组:

var arr = ['Apple', 'Google', 'Microsoft'];

for ( var i=0; i<arr.length; i++) {
    console.log(arr[i]);
}

👍 for 循环的 3 个条件都是可以省略的,如果没有退出循环的判断条件,就必须使用 break 语句终止循环,否则就是死循环:

var x = 0;
for (;;) { // 将无限循环下去
    if (x > 15) {
        console.log('x > 15: break');
        break; // 通过if判断来终止循环
    }
    x ++;
    console.log('x: ', x);
}

👍 也可以使用 continue 跳出本次循环,进入下一个循环:

var x = 0;
for (;;) { // 将无限循环下去
    if (x > 15) {
        console.log('x > 15: break');
        break; // 通过if判断来终止循环
    }
    x ++;
    if( x === 2){
      console.log('x === 2: continue');
      continue;
    }
    console.log('x: ', x);
}

二、for ...in 遍历

for 循环的一个变体是 for ... in 循环,它可以把一个对象的所有属性依次循环出来:

var o = {
    name: 'Felix',
    age: 18,
    city: 'Hefei'
};
for (var key in o) {
    if(key === 'age') {
      break;
    }
    console.log(key); // 'name', 'age', 'city'
}

由于 Array 也是对象,其元素的索引被视为对象的属性,因此,for ... in 循环可以直接循环出 Array 的索引:

var a = ['Apple', 'Banala', 'Cat'];
for (var i in a) {
    console.log(i); // '0', '1', '2'
    console.log(a[i]); // 'Apple', 'Banala', 'Cat'
}

请注意,for ... inArray 的循环得到的是 String 类型的值而不是 Number

👍 不过,ECMAScript 5.1 (ECMA-262) 给我们提供了更加简洁优雅的提取对象属性的方式: Object.keys()

var o = {
    name: 'Felix',
    age: 18,
    city: 'Hefei'
};
var a = ['Apple', 'Banala', 'Cat'];

console.log(Object.keys(o)); // ["name", "age", "city"]
console.log(Object.keys(a)); // ["0", "1", "2"]

三、while 循环

for 循环在明确循环的初始和结束条件时非常有用。而忽略了条件的 for 循环容易让人看不清循环的逻辑,这个时候推荐使用 while 循环

while 循环里只要指定条件为 true,循环就可以一直执行代码块。把本篇的第一段演示代码改写如下

var x = 0;
var i = 0;
while( i <= 100 ) {
  x = x + i;
  i ++;
}
x; // 5050
i; // 101

在循环体内部变量 i 不断自增,直到变为 101 时,不再满足 while 条件,退出循环。

也可以在循环体内使用 break 终止循环或 continue 跳出循环。

四、do ...while 循环

do { ... } while() 循环,它和 while 循环的唯一区别在于,不是在每次循环开始的时候判断条件,而是在每次循环完成的时候判断条件:

var x = 0;
var i = 0;
do{
  x = x + i;
  i ++;
} while( i <= 100 ) 
x; // 5050
i; // 101

👍 需要注意的是: 用 do { ... } while() 循环要小心,循环体至少执行1次,而 forwhile 循环则可能一次都不执行。

五、forEach() 遍历数组

forEach() 方法用于遍历数组的每个元素,并将元素传递给回调函数。

array.forEach(function(currentValue, [index], [arr]){
  // 回调函数的函数体
}, [thisValue])

例如:

var arr = ['Felix', 'Lucy', 'Bindy']
arr.forEach(console.log)

得到:

Felix 0  ["Felix", "Lucy", "Bindy"]
Lucy 1 ["Felix", "Lucy", "Bindy"]
Bindy 2 ["Felix", "Lucy", "Bindy"]

👍 注意: forEach() 对于空数组是不会执行回调函数的。

👍 跳出本次循环,不能使用 continue, 而是用 return false

var arr = ['Felix', 'Lucy', 'Bindy']
arr.forEach(function(val) {
  if( val === 'Lucy' ) {
    console.log('continue: Lucy');
    return false;
  }
  console.log(val);
})

上面的代码,遍历数组 arr , 当遇到一个元素的值完全等于字符串 Lucy 即跳出本次循环,进入下一次 Bindy 元素的循环。

👍 终止循环,使用 try catch:

var arr = ['Felix', 'Bindy', 3, 4, 5, 6, 'Lucy', 8, 9, 10];
try{
    arr.forEach(function(val) {
      if( val === 'Lucy' ) {
        throw new Error('exist from Lucy')
      }
      console.log(val);
    })
} catch (e) {
  console.log(e.message);
  if(e.message=='exist') throw e
} 

上面的代码,遍历数组 arr , 当遇到一个元素的值完全等于字符串 Lucy 时抛出一个 error 给 catch 捕捉到, 然后在 catch 里面 return,这样就能中止循环了。

@felix-cao
Copy link
Owner Author

felix-cao commented Feb 10, 2022

Jquery 中的 $.each

$.each = function( obj, callback ) { 
   var value, 
   i = 0, 
   length = obj.length, 
   isArray = isArraylike( obj ); 
   if ( isArray ) { // 迭代类数组
      for ( ; i < length; i++ ) { 
         value = callback.call( obj[ i ], i, obj[ i ] ); 
         if ( value === false ) { 
            break; 
         } 
      } 
   } else { 
      for ( i in obj ) { // 迭代 object 对象
         value = callback.call( obj[ i ], i, obj[ i ] ); 
         if ( value === false ) { 
            break; 
         } 
      } 
    } 
    return obj; 
};

上面代码的 value 值可以理解 return false 时, 停止当前循环跳到下一个循环。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant