zoukankan      html  css  js  c++  java
  • js 之 for循环

    js之 for循环


     普通for 循环


    语法

    for ([initialization]; [condition]; [final-expression])
       statement
    
    initialization
    一个表达式 (包含赋值语句) 或者变量声明。典型地被用于初始化一个计数器。该表达式可以使用var关键字声明新的变量。初始化中的变量不是该循环的局部变量,而是与for循环处在同样的作用域中。该表达式的结果无意义。
    condition
    一个条件表达式被用于确定每一次循环是否能被执行。如果该表达式的结果为true, statement 将被执行。 这个表达式是可选的。如果被忽略,那么就被认为永远为真。如果计算结果为假,那么执行流程将被跳到for语句结构后面的第一条语句。
    final-expression
    每次循环的最后都要执行的表达式。执行时机是在下一次condition的计算之前。通常被用于更新或者递增计数器变量。
    statement
    只要condition的结果为true就会被执行的语句。 要在循环体内执行多条语句,使用一个块语句({ ... })来包含要执行的语句。没有任何语句要执行,使用一个空语句(;)。

     事例

    for (var i = 0; i < 9; i++) {
       console.log(i);
       // more statements
    }

     for await...of


    语法

    for await (variable of iterable) { statement }
    variable在每次迭代时,将不同属性的值分配给变量
    iterable迭代其可迭代属性的对象。

    事例:
    async function* asyncGenerator() {
      var i = 0;
      while (i < 3) {
        yield i++;
      }
    }
    
    (async function() {
      for await (num of asyncGenerator()) {
        console.log(num);
      }
    })();
    // 0
    // 1
    // 2

     for each...in


    语法

    for each (variable in object) {
      statement
    }

    variable
    用来遍历属性值的变量,前面的var关键字是可选的.该变量是函数的局部变量而不是语句块的局部变量.
    object
    该对象的属性值会被遍历.
    statement
    遍历属性值时执行的语句. 如果想要执行多条语句, 请用({ ... }) 将多条语句括住.

     事例:

    var sum = 0;
    var obj = {prop1: 5, prop2: 13, prop3: 8};
    
    for each (var item in obj) {
      sum += item;
    }
    
    print(sum); // 输出"26",也就是5+13+8的值

    警告:永远不要使用for each...in语句遍历数组,仅用来遍历常规对象


     for...in


    语法

    for (variable in object) {...}

    variable
    在每次迭代时,将不同的属性名分配给变量。
    object
    被迭代枚举其属性的对象

    描述

    for...in 循环只遍历可枚举属性。像 Array和 Object使用内置构造函数所创建的对象都会继承自Object.prototypeString.prototype的不可枚举属性,例如 String 的 indexOf()  方法或 ObjecttoString()方法。循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性(更接近原型链中对象的属性覆盖原型属性)。

    删除,添加或者修改属性

    for...in 循环以任意序迭代一个对象的属性(请参阅delete运算符,了解为什么不能依赖于迭代的表面有序性,至少在跨浏览器设置中)。如果一个属性在一次迭代中被修改,在稍后被访问,其在循环中的值是其在稍后时间的值。一个在被访问之前已经被删除的属性将不会在之后被访问。在迭代进行时被添加到对象的属性,可能在之后的迭代被访问,也可能被忽略。通常,在迭代过程中最好不要在对象上进行添加、修改或者删除属性的操作,除非是对当前正在被访问的属性。这里并不保证是否一个被添加的属性在迭代过程中会被访问到,不保证一个修改后的属性(除非是正在被访问的)会在修改前或者修改后被访问,不保证一个被删除的属性将会在它被删除之前被访问。

    数组迭代和 for...in


    提示:for...in不应该用于迭代一个 Array,其中索引顺序很重要。

    数组索引只是具有整数名称的枚举属性,并且与通用对象属性相同。不能保证for ... in将以任何特定的顺序返回索引。for ... in循环语句将返回所有可枚举属性,包括非整数类型的名称和继承的那些。

    因为迭代的顺序是依赖于执行环境的,所以数组遍历不一定按次序访问元素。因此当迭代访问顺序很重要的数组时,最好用整数索引去进行for循环(或者使用 Array.prototype.forEach() 或 for...of 循环)。

    仅迭代自身的属性

    如果你只要考虑对象本身的属性,而不是它的原型,那么使用 getOwnPropertyNames() 或执行 hasOwnProperty() 来确定某属性是否是对象本身的属性(也能使用propertyIsEnumerable)。或者,如果你知道不会有任何外部代码干扰,您可以使用检查方法扩展内置原型。

    事例

    var obj = {a:1, b:2, c:3};
        
    for (var prop in obj) {
      console.log("obj." + prop + " = " + obj[prop]);
    }
    
    // Output:
    // "obj.a = 1"
    // "obj.b = 2"
    // "obj.c = 3"
    var triangle = {a: 1, b: 2, c: 3};
    
    function ColoredTriangle() {
      this.color = 'red';
    }
    
    ColoredTriangle.prototype = triangle;
    
    var obj = new ColoredTriangle();
    
    for (var prop in obj) {
      if (obj.hasOwnProperty(prop)) {
        console.log(`obj.${prop} = ${obj[prop]}`);
      } 
    }
    
    // Output:
    // "obj.color = red"

     for...of

    语法

    for (variable of iterable) {
        //statements
    }
    variable在每次迭代中,将不同属性的值分配给变量。iterable被迭代枚举其属性的对象。

    示例

    迭代Array

    let iterable = [10, 20, 30];
    
    for (let value of iterable) {
        value += 1;
        console.log(value);
    }
    // 11
    // 21
    // 31

    如果你不想修改语句块中的变量 , 也可以使用const代替let

    let iterable = [10, 20, 30];
    
    for (const value of iterable) {
      console.log(value);
    }
    // 10
    // 20
    // 30

    迭代String

    let iterable = "boo";
    
    for (let value of iterable) {
      console.log(value);
    }
    // "b"
    // "o"
    // "o"

    迭代 TypedArray

    let iterable = new Uint8Array([0x00, 0xff]);
    
    for (let value of iterable) {
      console.log(value);
    }
    // 0
    // 255

    迭代Map

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

    迭代 Set

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

    迭代 arguments 对象

    (function() {
      for (let argument of arguments) {
        console.log(argument);
      }
    })(1, 2, 3);
    
    // 1
    // 2
    // 3

    迭代 DOM 集合

    迭代 DOM 元素集合,比如一个NodeList对象:下面的例子演示给每一个 article 标签内的 p 标签添加一个 "read" 类。

    //注意:这只能在实现了NodeList.prototype[Symbol.iterator]的平台上运行
    let articleParagraphs = document.querySelectorAll("article > p");
    
    for (let paragraph of articleParagraphs) {
      paragraph.classList.add("read");
    }

    关闭迭代器

    对于for...of的循环,可以由breakthrow 或return终止。在这些情况下,迭代器关闭。

    function* foo(){ 
      yield 1; 
      yield 2; 
      yield 3; 
    }; 
    
    for (let o of foo()) { 
      console.log(o); 
      break; // closes iterator, triggers return
    }

    迭代生成器

    你还可以迭代一个生成器:

    function* fibonacci() { // 一个生成器函数
        let [prev, curr] = [0, 1];
        for (;;) { // while (true) {
            [prev, curr] = [curr, prev + curr];
            yield curr;
        }
    }
     
    for (let n of fibonacci()) {
         console.log(n); 
        // 当n大于1000时跳出循环
        if (n >= 1000)
            break;
    }

    不要重用生成器

    生成器不应该重用,即使for...of循环的提前终止,例如通过break关键字。在退出循环后,生成器关闭,并尝试再次迭代,不会产生任何进一步的结果。

    var gen = (function *(){
        yield 1;
        yield 2;
        yield 3;
    })();
    for (let o of gen) {
        console.log(o);
        break;//关闭生成器
    } 
    
    //生成器不应该重用,以下没有意义!
    for (let o of gen) {
        console.log(o);
    }

    迭代其他可迭代对象

    你还可以迭代显式实现可迭代协议的对象:

    var iterable = {
      [Symbol.iterator]() {
        return {
          i: 0,
          next() {
            if (this.i < 3) {
              return { value: this.i++, done: false };
            }
            return { value: undefined, done: true };
          }
        };
      }
    };
    
    for (var value of iterable) {
      console.log(value);
    }
    // 0
    // 1
    // 2

    for...offor...in的区别

    无论是for...in还是for...of语句都是迭代一些东西。它们之间的主要区别在于它们的迭代方式。

    for...in 语句以原始插入顺序迭代对象的可枚举属性。

    for...of 语句遍历可迭代对象定义要迭代的数据。

    以下示例显示了与Array一起使用时,for...of循环和for...in循环之间的区别。

    Object.prototype.objCustom = function() {}; 
    Array.prototype.arrCustom = function() {};
    
    let iterable = [3, 5, 7];
    iterable.foo = 'hello';
    
    for (let i in iterable) {
      console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
    }
    
    for (let i in iterable) {
      if (iterable.hasOwnProperty(i)) {
        console.log(i); // logs 0, 1, 2, "foo"
      }
    }
    
    for (let i of iterable) {
      console.log(i); // logs 3, 5, 7
    }
    Object.prototype.objCustom = function() {};
    Array.prototype.arrCustom = function() {}; 
    
    let iterable = [3, 5, 7]; 
    iterable.foo = 'hello';

    每个对象将继承objCustom属性,并且作为Array的每个对象将继承arrCustom属性,因为将这些属性添加到Object.prototypeArray.prototype。由于继承和原型链,对象iterable继承属性objCustomarrCustom

    for (let i in iterable) {
      console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom" 
    }

    此循环仅以原始插入顺序记录iterable 对象的可枚举属性。它不记录数组元素357 或hello,因为这些不是枚举属性。但是它记录了数组索引以及arrCustomobjCustom。如果你不知道为什么这些属性被迭代,array iteration and for...in中有更多解释。

    for (let i in iterable) {
      if (iterable.hasOwnProperty(i)) {
        console.log(i); // logs 0, 1, 2, "foo"
      }
    }

    这个循环类似于第一个,但是它使用hasOwnProperty() 来检查,如果找到的枚举属性是对象自己的(不是继承的)。如果是,该属性被记录。记录的属性是012foo,因为它们是自身的属性(不是继承的)。属性arrCustomobjCustom不会被记录,因为它们是继承的

    for (let i of iterable) {
      console.log(i); // logs 3, 5, 7 
    }

    该循环迭代并记录iterable作为可迭代对象定义的迭代值,这些是数组元素 357,而不是任何对象的属性


     摘取自MDN


  • 相关阅读:
    9.11 eventbus
    9.10,,,实现new instanceof apply call 高阶函数,偏函数,柯里化
    9.9 promise实现 写完了传到gitee上面了,这里这个不完整
    9.5cors配置代码
    9.5 jsonp 实现
    9.5 http tcp https总结
    9.3 es6 class一部分 and es5 class 发布订阅
    8.30 cookie session token jwt
    8.30vue响应式原理
    warning: LF will be replaced by CRLF in renard-wx/project.config.json. The file will have its original line endings in your working directory
  • 原文地址:https://www.cnblogs.com/zero-vic/p/9948574.html
Copyright © 2011-2022 走看看