# 循環
## 循環
要計算1+2+3,我們可以直接寫表達式:
```
1 + 2 + 3; // 6
```
要計算1+2+3+...+10,勉強也能寫出來。
但是,要計算1+2+3+...+10000,直接寫表達式就不可能了。
為了讓計算機能計算成千上萬次的重復運算,我們就需要循環語句。
JavaScript的循環有兩種,一種是`for`循環,通過初始條件、結束條件和遞增條件來循環執行語句塊:
```
var x = 0;
var i;
for (i=1; i<=10000; i++) {
x = x + i;
}
x; // 50005000
```
讓我們來分析一下`for`循環的控制條件:
* i=1 這是初始條件,將變量i置為1;
* i<=10000 這是判斷條件,滿足時就繼續循環,不滿足就退出循環;
* i++ 這是每次循環后的遞增條件,由于每次循環后變量i都會加1,因此它終將在若干次循環后不滿足判斷條件`i<=10000`而退出循環。
## 練習
利用`for`循環計算`1 * 2 * 3 * ... * 10`的結果:
```
'use strict';
var x = ?;
var i;
for ...
if (x === 3628800) {
alert('1 x 2 x 3 x ... x 10 = ' + x);
}
else {
alert('計算錯誤');
}
```
`for`循環最常用的地方是利用索引來遍歷數組:
```
var arr = ['Apple', 'Google', 'Microsoft'];
var i, x;
for (i=0; i<arr.length; i++) {
x = arr[i];
alert(x);
}
```
`for`循環的3個條件都是可以省略的,如果沒有退出循環的判斷條件,就必須使用`break`語句退出循環,否則就是死循環:
```
var x = 0;
for (;;) { // 將無限循環下去
if (x > 100) {
break; // 通過if判斷來退出循環
}
x ++;
}
```
## for ... in
`for`循環的一個變體是`for ... in`循環,它可以把一個對象的所有屬性依次循環出來:
```
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
alert(key); // 'name', 'age', 'city'
}
```
要過濾掉對象繼承的屬性,用`hasOwnProperty()`來實現:
```
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
if (o.hasOwnProperty(key)) {
alert(key); // 'name', 'age', 'city'
}
}
```
由于`Array`也是對象,而它的每個元素的索引被視為對象的屬性,因此,`for ... in`循環可以直接循環出`Array`的索引:
```
var a = ['A', 'B', 'C'];
for (var i in a) {
alert(i); // '0', '1', '2'
alert(a[i]); // 'A', 'B', 'C'
}
```
_請注意_,`for ... in`對`Array`的循環得到的是`String`而不是`Number`。
## while
`for`循環在已知循環的初始和結束條件時非常有用。而上述忽略了條件的`for`循環容易讓人看不清循環的邏輯,此時用`while`循環更佳。
`while`循環只有一個判斷條件,條件滿足,就不斷循環,條件不滿足時則退出循環。比如我們要計算100以內所有奇數之和,可以用while循環實現:
```
var x = 0;
var n = 99;
while (n > 0) {
x = x + n;
n = n - 2;
}
x; // 2500
```
在循環內部變量`n`不斷自減,直到變為`-1`時,不再滿足`while`條件,循環退出。
## do ... while
最后一種循環是`do { ... } while()`循環,它和`while`循環的唯一區別在于,不是在每次循環開始的時候判斷條件,而是在每次循環完成的時候判斷條件:
```
var n = 0;
do {
n = n + 1;
} while (n < 100);
n; // 100
```
用`do { ... } while()`循環要小心,循環體會至少執行1次,而`for`和`while`循環則可能一次都不執行。
## 練習
請利用循環遍歷數組中的每個名字,并顯示`Hello, xxx!`:
```
'use strict';
var arr = ['Bart', 'Lisa', 'Adam'];
```
請嘗試`for`循環和`while`循環,并以正序、倒序兩種方式遍歷。
## 小結
循環是讓計算機做重復任務的有效的方法,有些時候,如果代碼寫得有問題,會讓程序陷入“死循環”,也就是永遠循環下去。JavaScript的死循環會讓瀏覽器無法正常顯示或執行當前頁面的邏輯,有的瀏覽器會直接掛掉,有的瀏覽器會在一段時間后提示你強行終止JavaScript的執行,因此,要特別注意死循環的問題。
在編寫循環代碼時,務必小心編寫初始條件和判斷條件,尤其是邊界值。特別注意`i < 100`和`i <= 100`是不同的判斷邏輯。
- JavaScript教程
- JavaScript簡介
- 快速入門
- 基本語法
- 數據類型和變量
- 字符串
- 數組
- 對象
- 條件判斷
- 循環
- Map和Set
- iterable
- 函數
- 函數定義和調用
- 變量作用域
- 方法
- 高階函數
- map/reduce
- filter
- sort
- 閉包
- 箭頭函數
- generator
- 標準對象
- Date
- RegExp
- JSON
- 面向對象編程
- 創建對象
- 原型繼承
- 瀏覽器
- 瀏覽器對象
- 操作DOM
- 更新DOM
- 插入DOM
- 刪除DOM
- 操作表單
- 操作文件
- AJAX
- Promise
- Canvas
- jQuery
- 選擇器
- 層級選擇器
- 查找和過濾
- 操作DOM
- 修改DOM結構
- 事件
- 動畫
- 擴展
- underscore
- Collections
- Arrays
- Functions
- Objects
- Chaining
- Node.js
- 安裝Node.js和npm
- 第一個Node程序
- 模塊
- 基本模塊
- fs
- stream
- http
- buffer
- Web開發
- koa
- mysql
- swig
- 自動化工具
- 期末總結
- Python 2.7教程
- Python簡介
- 安裝Python
- Python解釋器
- 第一個Python程序
- 使用文本編輯器
- 輸入和輸出
- Python基礎
- 數據類型和變量
- 字符串和編碼
- 使用list和tuple
- 條件判斷和循環
- 使用dict和set
- 函數
- 調用函數
- 定義函數
- 函數的參數
- 遞歸函數
- 高級特性
- 切片
- 迭代
- 列表生成式
- 生成器
- 函數式編程
- 高階函數
- map/reduce
- filter
- sorted
- 返回函數
- 匿名函數
- 裝飾器
- 偏函數
- 模塊
- 使用模塊
- 安裝第三方模塊
- 使用__future__
- 面向對象編程
- 類和實例
- 訪問限制
- 繼承和多態
- 獲取對象信息
- 面向對象高級編程
- 使用__slots__
- 使用@property
- 多重繼承
- 定制類
- 使用元類
- 錯誤、調試和測試
- 錯誤處理
- 調試
- 單元測試
- 文檔測試
- IO編程
- 文件讀寫
- 操作文件和目錄
- 序列化
- 進程和線程
- 多進程
- 多線程
- ThreadLocal
- 進程 vs. 線程
- 分布式進程
- 正則表達式
- 常用內建模塊
- collections
- base64
- struct
- hashlib
- itertools
- XML
- HTMLParser
- 常用第三方模塊
- PIL
- 圖形界面
- 網絡編程
- TCP/IP簡介
- TCP編程
- UDP編程
- 電子郵件
- SMTP發送郵件
- POP3收取郵件
- 訪問數據庫
- 使用SQLite
- 使用MySQL
- 使用SQLAlchemy
- Web開發
- HTTP協議簡介
- HTML簡介
- WSGI接口
- 使用Web框架
- 使用模板
- 協程
- gevent
- 實戰
- Day 1 - 搭建開發環境
- Day 2 - 編寫數據庫模塊
- Day 3 - 編寫ORM
- Day 4 - 編寫Model
- Day 5 - 編寫Web框架
- Day 6 - 添加配置文件
- Day 7 - 編寫MVC
- Day 8 - 構建前端
- Day 9 - 編寫API
- Day 10 - 用戶注冊和登錄
- Day 11 - 編寫日志創建頁
- Day 12 - 編寫日志列表頁
- Day 13 - 提升開發效率
- Day 14 - 完成Web App
- Day 15 - 部署Web App
- Day 16 - 編寫移動App
- 期末總結
- Python3教程
- Python簡介
- 安裝Python
- Python解釋器
- 第一個Python程序
- 使用文本編輯器
- Python代碼運行助手
- 輸入和輸出
- Python基礎
- 數據類型和變量
- 字符串和編碼
- 使用list和tuple
- 條件判斷
- 循環
- 使用dict和set
- 函數
- 調用函數
- 定義函數
- 函數的參數
- 遞歸函數
- 高級特性
- 切片
- 迭代
- 列表生成式
- 生成器
- 迭代器
- 函數式編程
- 高階函數
- map/reduce
- filter
- sorted
- 返回函數
- 匿名函數
- 裝飾器
- 偏函數
- 模塊
- 使用模塊
- 安裝第三方模塊
- 面向對象編程
- 類和實例
- 訪問限制
- 繼承和多態
- 獲取對象信息
- 實例屬性和類屬性
- 面向對象高級編程
- 使用__slots__
- 使用@property
- 多重繼承
- 定制類
- 使用枚舉類
- 使用元類
- 錯誤、調試和測試
- 錯誤處理
- 調試
- 單元測試
- 文檔測試
- IO編程
- 文件讀寫
- StringIO和BytesIO
- 操作文件和目錄
- 序列化
- 進程和線程
- 多進程
- 多線程
- ThreadLocal
- 進程 vs. 線程
- 分布式進程
- 正則表達式
- 常用內建模塊
- datetime
- collections
- base64
- struct
- hashlib
- itertools
- XML
- HTMLParser
- urllib
- 常用第三方模塊
- PIL
- virtualenv
- 圖形界面
- 網絡編程
- TCP/IP簡介
- TCP編程
- UDP編程
- 電子郵件
- SMTP發送郵件
- POP3收取郵件
- 訪問數據庫
- 使用SQLite
- 使用MySQL
- 使用SQLAlchemy
- Web開發
- HTTP協議簡介
- HTML簡介
- WSGI接口
- 使用Web框架
- 使用模板
- 異步IO
- 協程
- asyncio
- async/await
- aiohttp
- 實戰
- Day 1 - 搭建開發環境
- Day 2 - 編寫Web App骨架
- Day 3 - 編寫ORM
- Day 4 - 編寫Model
- Day 5 - 編寫Web框架
- Day 6 - 編寫配置文件
- Day 7 - 編寫MVC
- Day 8 - 構建前端
- Day 9 - 編寫API
- Day 10 - 用戶注冊和登錄
- Day 11 - 編寫日志創建頁
- Day 12 - 編寫日志列表頁
- Day 13 - 提升開發效率
- Day 14 - 完成Web App
- Day 15 - 部署Web App
- Day 16 - 編寫移動App
- FAQ
- 期末總結
- Git教程
- Git簡介
- Git的誕生
- 集中式vs分布式
- 安裝Git
- 創建版本庫
- 時光機穿梭
- 版本回退
- 工作區和暫存區
- 管理修改
- 撤銷修改
- 刪除文件
- 遠程倉庫
- 添加遠程庫
- 從遠程庫克隆
- 分支管理
- 創建與合并分支
- 解決沖突
- 分支管理策略
- Bug分支
- Feature分支
- 多人協作
- 標簽管理
- 創建標簽
- 操作標簽
- 使用GitHub
- 自定義Git
- 忽略特殊文件
- 配置別名
- 搭建Git服務器
- 期末總結