[TOC]
# for循环的基本用法
要计算1+2+3,我们可以直接写表达式:
~~~
1 + 2 + 3; // 6
~~~
要计算1+2+3+...+10,勉强也能写出来。
但是,要计算1+2+3+...+10000,直接写表达式就不可能了。
为了让计算机能计算成千上万次的重复运算,我们就需要循环语句。
JavaScript的循环有两种,一种是`for`循环,通过初始条件、结束条件和递增条件来循环执行语句块:
~~~js
let x = 0;
for (let i=1; i<=10000; i++) {
x = x + i;
}
x; // 50005000
~~~
让我们来分析一下`for`循环的控制条件:
* let i=1 这是初始条件,将定义局部变量i,并将变量i置为1;
* i<=10000 这是判断条件,满足时就继续循环,不满足就退出循环;
* i++ 这是每次循环后的递增条件,由于每次循环后变量i都会加1,因此它终将在若干次循环后不满足判断条件`i<=10000`而退出循环。
## 练习
利用`for`循环计算`1 * 2 * 3 * ... * 10`的结果:
~~~
'use strict';
let x = ?;
let i;
for ...
if (x === 3628800) {
alert('1 x 2 x 3 x ... x 10 = ' + x);
}
else {
alert('计算错误');
}
~~~
`for`循环最常用的地方是利用索引来遍历数组:
~~~
const arr = ['Apple', 'Google', 'Microsoft'];
for (let i=0; i<arr.length; i++) {
const x = arr[i];
alert(x);
}
~~~
`for`循环的3个条件都是可以省略的,如果没有退出循环的判断条件,就必须使用`break`语句退出循环,否则就是死循环:
~~~
let x = 0;
for (;;) { // 将无限循环下去
if (x > 100) {
break; // 通过if判断来退出循环
}
x ++;
}
~~~
# forEach
在ES5中引入。给定一个数组,您可以使用list.forEach()迭代其属性:
~~~
const list = ['a', 'b', 'c']
list.forEach((item, index) =>{
console.log(item) //value
console.log(index) //index
})
//index is optional
list.forEach(item => console.log(item))
~~~
> 不过需要注意的是你无法摆脱这个循环。
直接使用`iterable`内置的`forEach`方法,它接收一个函数,每次迭代就自动回调该函数。以`Array`为例:
```js
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
alert(element);
});
```
*注意*,`forEach()`方法是ES5.1标准引入的,你需要测试浏览器是否支持。
`Set`与`Array`类似,但`Set`没有索引,因此回调函数的前两个参数都是元素本身:
~~~
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
alert(element);
});
~~~
`Map`的回调函数参数依次为`value`、`key`和`map`本身:
~~~
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
alert(value);
});
~~~
如果对某些参数不感兴趣,由于JavaScript的函数调用不要求参数必须一致,因此可以忽略它们。例如,只需要获得`Array`的`element`:
~~~
var a = ['A', 'B', 'C'];
a.forEach(function (element) {
alert(element);
});
~~~
# for ... in
`for`循环的一个变体是`for ... in`循环,它可以把一个对象的所有属性依次循环出来:
~~~
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
alert(key); // 'name', 'age', 'city'
}
~~~
要过滤掉对象继承的属性,用`hasOwnProperty()`来实现:
~~~
const obj = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
console.log(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`。
# for...of语句
for...of语句在可迭代对象(包括 Array, Map, Set, String, TypedArray,arguments 对象等等)上创建一个迭代循环,对每个不同属性的属性值,调用一个自定义的有执行语句的迭代挂钩.
for...of语法是为各种collection对象专门定制的,并不适用于所有的object.它会以这种方式迭代出任何拥有`[Symbol.iterator]` 属性的collection对象的每个元素。
~~~
//variable:每一次迭代,不同属性的属性值会被赋值给该变量.
//object:一个可迭代对象.
for (variable of object) {
statement
}
~~~
遍历 Array:
~~~
let iterable = [10, 20, 30];
for (let value of iterable) {
console.log(value);
}
// 10
// 20
// 30
~~~
如果你不修改语句块中的变量 , 也可以使用 const 代替 let。注意不要用var,会导致变量提升副作用。
~~~
let iterable = [10, 20, 30];
for (const value of iterable) {
console.log(value);
}
// 10
// 20
// 30
遍历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
~~~
# for...of与for...in的区别
for...in循环会遍历一个object所有的可枚举属性。
for...of语法是为各种collection对象专门定制的,并不适用于所有的object.它会以这种方式迭代出任何拥有`[Symbol.iterator] `属性的collection对象的每个元素。
下面的例子演示了for...of 循环和 for...in 循环的区别。for...in 遍历(当前对象及其原型上的)每一个属性名称,而 for...of遍历(当前对象上的)每一个属性值:
~~~
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 of iterable) {
console.log(i); // logs 3, 5, 7
}
~~~
> for .. of与for ... in 语句一定注意弄清楚使用的环境,否则会得到意想不到的结果。.
你可能会有疑问,`for ... of`循环和`for ... in`循环有何区别?
`for ... in`循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个`Array`数组实际上也是一个对象,它的每个元素的索引被视为一个属性。
当我们手动给`Array`对象添加了额外的属性后,`for ... in`循环将带来意想不到的意外效果:
```js
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
alert(x); // '0', '1', '2', 'name'
}
```
`for ... in`循环将把`name`包括在内,但`Array`的`length`属性却不包括在内。
`for ... of`循环则完全修复了这些问题,它只循环集合本身的元素:
```js
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a) {
alert(x); 'A', 'B', 'C'
}
```
这就是为什么要引入新的`for ... of`循环。
# 小结
循环是让计算机做重复任务的有效的方法,有些时候,如果代码写得有问题,会让程序陷入“死循环”,也就是永远循环下去。JavaScript的死循环会让浏览器无法正常显示或执行当前页面的逻辑,有的浏览器会直接挂掉,有的浏览器会在一段时间后提示你强行终止JavaScript的执行,因此,要特别注意死循环的问题。
- 内容介绍
- EcmaScript基础
- 快速入门
- 常量与变量
- 字符串
- 函数的基本概念
- 条件判断
- 数组
- 循环
- while循环
- for循环
- 函数基础
- 对象
- 对象的方法
- 函数
- 变量作用域
- 箭头函数
- 闭包
- 高阶函数
- map/reduce
- filter
- sort
- Promise
- 基本对象
- Arguments 对象
- 剩余参数
- Map和Set
- Json基础
- RegExp
- Date
- async
- callback
- promise基础
- promise-api
- promise链
- async-await
- 项目实践
- 标签系统
- 远程API请求
- 面向对象编程
- 创建对象
- 原型继承
- 项目实践
- Classes
- 构造函数
- extends
- static
- 项目实践
- 模块
- import
- export
- 项目实践
- 第三方扩展库
- immutable
- Vue快速入门
- 理解MVVM
- Vue中的MVVM模型
- Webpack+Vue快速入门
- 模板语法
- 计算属性和侦听器
- Class 与 Style 绑定
- 条件渲染
- 列表渲染
- 事件处理
- 表单输入绑定
- 组件基础
- 组件注册
- Prop
- 自定义事件
- 插槽
- 混入
- 过滤器
- 项目实践
- 标签编辑
- iView
- iView快速入门
- 课程讲座
- 环境配置
- 第3周 Javascript快速入门