天天看点

birt脚本for循环语句_③ - for、while - JS循环语句

# [1]个人学习笔记,对基础知识的整理和巩固。

JS有几种循环语句:

  • for
  • for...in
  • for...of(ES6 IE不支持)
  • while
  • do...while
  • for each...in[2] (已废弃,不述)
  • for await...in[3](异步,暂不述)

▉ while[4]

语法:

while ( condition) statement

条件为真时执行语句,如此往复,直到条件为假。

多行语句可以用大括号包裹。

▉ do...while[5]

语法:

do statement

while ( condition);

先执行一次,条件为真时重复执行,直到条件为假。

类似while,但至少执行一次。

▉ for[6]

最经典的for语句,语法:

for ([ initialization]; [ condition]; [ final-expression]) statement

先执行[initialization],然后在[condition]为真时,执行[statement]语句。

每次[statement]执行完毕后运行一次[final-expression],之后再次检测[condition],为真时再次执行[statement],以此往复,直到[condition]为假。

执行顺序示例:

var i=0;
for (console.log(1); console.log(2) || i < 1; console.log(4)||i++) {
    console.log(3);
}
           

依次输出1、2、3、4 之后,输出2 ,然后结束(条件不符合,跳出)。

console.log()返回值为undefined,为假。

*第一次执行也会检查[condition]。

▉ for...of[7](ES6)

for ( variable of iterable) statement

for...of可用于迭代数组和其他任何可迭代对象[8](包括 Array,Map,Set,String,TypedArray,arguments 对象等等,也可以自定义可迭代对象,如jQuery对象(好像是自某个版本之后支持))。

基于ES6标准,IE不支持。

它非常好用。

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

依次输出1、2、3。

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

用于迭代数组之外的其他可迭代对象的话,暂时不述(我还没研究到),可先参考MDN 。

▉ for...in[9]

for ( variable in object) statement

for...in用于遍历对象的(及其原型链上继承的)可枚举属性,variable为相应的属性名。

所谓可枚举属性可参照:属性的可枚举性和所有权 - MDN

如下例:

let obj={
    a:1,
    b:2,
    __proto__:{ // __proto__为非正当用法 仅为此处简单示例
        c:3
    }
}

for (let name in obj) {
    console.log(`${name}:${obj[name]}`);
}
           

将依次输出:a:1, b:2, c:3 。

MDN不建议将for...in用于遍历数组,可使用for循环或for...of以及forEach() 。

▉ break[10]

break [ label];

break语句用于中止当前循环、

switch

语句、

label

语句,并把程序控制流转到紧接着被中止语句后面的语句(MDN)。

可用于以上所述循环,switch语句,以及label标记的循环或语句块(label见下文)。

▉ continue[11]

continue [ label];

在for循环中,控制流跳转到更新语句;在while循环中,控制流跳转回条件判断。(MDN)

可用于以上所述循环,也可以搭配label使用(label见下文)。

▉ label[12]

label : statement

标签(label)用于标记一个循环或语句块,然后在break和continue语句中使用它。

如下例:

lable1:{
    console.log(1); // 输出1
    break lable1; // 跳出语句块
    console.log(2); // 未运行 不输出
}
           

一个来自MDN的示例:

outer_block:{
  inner_block:{
    console.log ('1');
    break outer_block;      // breaks out of both inner_block and outer_block
    console.log (':-(');    // skipped
  }
  console.log ('2');        // skipped
}
           

上例只输出1 。

lable只在其标记的语句块或循环中有效。

用label来标记语句块时,只能搭配break使用,不能搭配continue。

continue label;

语句只适用于循环内。

用label来标记循环(来自MDN):

var i, j;

loop1:
for (i = 0; i < 3; i++) {      //The first for statement is labeled "loop1"
   loop2:
   for (j = 0; j < 3; j++) {   //The second for statement is labeled "loop2"
      if (i == 1 && j == 1) {
         break loop1; // 直接跳出外部循环
      }
      console.log("i = " + i + ", j = " + j);
   }
}

// Output is:
//   "i = 0, j = 0"
//   "i = 0, j = 1"
//   "i = 0, j = 2"
//   "i = 1, j = 0"
// Notice the difference with the previous continue example
           

一般情况下,如果不搭配label,当循环嵌套时,内部循环体内使用break或continue只能跳出内部循环,而搭配使用label标签,可以在内部循环中跳出外部循环。

尽管如此,label仍然极少使用。

也可以用于while等循环。

#[1]

▉ let与for循环

首先是经典例子:

for (var i = 0; i < 3; i++) {
    setTimeout(()=>{
        console.log(i);
    }
    );
}
console.log(i); // 输出3
           

将输出3, 3, 3, 3 。

setTimeout的代码将在循环后依次执行,而var定义的变量i被后续的循环给更改了,所以全是3。

只要将var改为let:

for (let i = 0; i < 3; i++) {
    setTimeout(()=>{
        console.log(i);
    }
    );
}
           

将依次输出0, 1, 2 。

这其实挺让人疑惑,按照我们理解的for循环,理论上 let i=0 只执行了一次,所以应当只定义了一个i,为什么会有三个不同的值。

for循环似乎针对let作了特殊的处理。

首先来研究一下它的作用域:

{
    let i;
    for (let i = 0; i < 3; i++) {
        let i;
    }
}
           

上述代码不会报错,而let不能在同一作用域内重复声明,所以我们知道上例三处声明分别处于不同的作用域。

首先for处在一个无形的块作用域中,其代码块又是一个子块作用域,好像是这样:

{for (let i = 0; i < 3; i++) {
    // 子块
}} // 似乎有一个无形的块
           

按照这种逻辑的话,小括号里的声明应该是在外层,为什么有三个不同的结果呢?

另外,在一次循环中对变量做出的改变,也仍然会影响到下一次循环,像这样:

for (let i = 0; i < 3; i++) {
    console.log(i);
    i++;
}
           

上例将输出 0, 2 。

经过测试和总结,let声明的变量似乎经历了中转,像这样:

for (let i = 0; i < 3; i++) {
    setTimeout(()=>{
        console.log(i);
    }
    )
}

// 就好像:

for (let i = 0; i < 3; i++) {
    let _i = i;
    {
        let i = _i;

        // ↓代码块
        setTimeout(()=>{
            console.log(i);
        }
        )
        // ↑

        _i = i;
    }
    i = _i; // 如果代码块中进行了改变,则此处进行
}

// 简便看:
for (let i = 0; i < 3; i++) {

    // 处理1:对变量进行中转 创建一个仅在本次循环作用的变量i 并且等于原变量 i

    // ↓代码块
    // 本次循环中i是子变量i
    setTimeout(()=>{
        console.log(i);
    }
    )
    // ↑

    // 处理2:令原变量i的值等于子变量i 即,如果本次循环内i发生改变,则 原变量i 也将发生改变

}
           

看起来就是这样,这种理解暂时没有发现什么问题,很完美。

另外还有几点:

  • 这种特殊处理只会针对在小括号里初始化语句中声明的变量:
let i;

for (i = 0; i < 3; i++) {
    setTimeout(()=>{
        console.log(i);
    }
    );
}
           

上例将输出3, 3, 3 。

  • 如果声明多个变量,它们都会被进行特殊处理。
  • 如果是数组或对象等等,仍然都是引用,所以可能都还是同一个,但是仍然可以认为经过了处理,因为引用也可能在循环中被改变。
  • for...of和for...in之类的类同,只不过少了循环执行后的部分(处理2),因为不论怎么改变下一次循环都会重新取值,所以没有意义。
  • const类同,但是不能改变。

最后的示例:

for (let a = 0, b = "", c = [], d; a < 3; a++) {
    setTimeout(()=>{
        console.log(a, b, c, d);
    });
    b += "1";
    c.push(1);
    d = [a];
}
           

输出结果:

birt脚本for循环语句_③ - for、while - JS循环语句

参考

  1. ^ab#1 https://zhuanlan.zhihu.com/c_1279094787908583424
  2. ^for each...in - MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for_each...in
  3. ^for await...of - MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for-await...of
  4. ^while - MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/while
  5. ^do...while - MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/do...while
  6. ^for - MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for
  7. ^for...of https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/for...of
  8. ^迭代协议 - MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols
  9. ^for...in - MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/statements/for...in
  10. ^break - MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/statements/break
  11. ^continue - MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/statements/continue
  12. ^label - MDN https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/statements/label

继续阅读