js 循环
# js 数组循环
# 1. for
适用范围:数组
简介:
1、for 有三个表达式:① 声明循环变量;② 判断循环条件;③ 更新循环变量;三个表达式之间,用;分割,for 循环三个表达式都可以省略,但是两个“;”缺一不可。
2、for 循环的执行特点:先判断再执行,与 while 相同
3、for 循环三个表达式都可以有多部分组成,第二部分多个判断条件用&& ||连接,第一三部分用逗号分割;
# 2. for of
适用范围:Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象等拥有迭代器对象(iterator)的集合
ES6 借鉴 C++、Java、C# 和 Python 语言,引入了 for...of 循环,作为遍历所有数据结构的统一的方法。
一个数据结构只要部署了 Symbol.iterator 属性,就被视为具有 iterator 接口,就可以用 for...of 循环遍历它的成员。 也就是说,for...of 循环内部调用的是数据结构的 Symbol.iterator 方法。 for...of 循环可以使用的范围包括数组、Set 和 Map 结构、某些类似数组的对象(比如 arguments 对象、DOM NodeList 对象)、后文的 Generator 对象,以及字符串。
for of 怎么遍历对象?
- 使用 Object.keys
const obj = {
a: 1,
b: 2,
c: 3,
};
for (let i of Object.keys(obj)) {
console.log(i);
// 1
// 2
// 3
}
2
3
4
5
6
7
8
9
10
11
12
- 实现 iterator 接口
const obj = {
e: 5,
f: 6,
};
newObj[Symbol.iterator] = function*() {
let keys = Object.keys(this);
for (let i = 0, l = keys.length; i < l; i++) {
yield {
key: keys[i],
value: this[keys[i]],
};
}
};
for (let { key, value } of newObj) {
console.log(key, value);
}
// 输出结果
// e 5
// f 6
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 3. map
适用范围:数组
以一个数组的每一项为基础,构造出一个新数组。
- 语法:
arr.map(function(self,index,arr){},this);
和 forEach 一致
self:数组当前遍历的元素,默认从左往右依次获取数组元素。
index:数组当前元素的索引,第一个元素索引为 0,依次类推。
arr:当前遍历的数组。
this:回调函数中 this 指向。
# 4. forEach
适用范围:数组
forEach 对数组的每一项执行同样的操作
- 语法:
arr.forEach(function(self,index,arr){},this);
self:数组当前遍历的元素,默认从左往右依次获取数组元素。
index:数组当前元素的索引,第一个元素索引为 0,依次类推。
arr:当前遍历的数组。
this:回调函数中 this 指向。
注意点
- forEach 不支持 break
- forEach 中使用 return 无效
- forEach 删除自身元素 index 不会被重置
可改变原数组情况:
var a = [1, "1", { num: 1 }, true];
a.forEach((item, index, arr) => {
item.num = 2;
item = 2;
});
console.log(a);
// [1,'1',{num:2},true]
// 改变原因:由于对象是引用类型,新对象和旧对象指向的都是同一个地址,所以新对象把num变成了2,原数组中的对象也改变了
var a = [1, 2, 3, 4, 5];
a.forEach((item, index, arr) => {
arr[index] = item * 2;
});
console.log(a);
// [2,4,6,8,10]
// 改变原因:同上,参数中的arr也只是原数组的一个拷贝,如果修改数组中的某一项则原数组也改变因为指向同一引用地址
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
不可改变原数组情况:
var a = [1, 2, 3, 4, 5];
a.forEach((item) => {
item = item * 2;
});
console.log(a);
// [1,2,3,4,5]
// 不改变原因:因为item的值并不是相应的原数组中的值,而是重新建立的一个新变量,值和原数组相同。
var a = [1, "1", { num: 1 }, true];
a.forEach((item, index, arr) => {
item = 2;
});
console.log(a);
// [1,'1',{num:1},true]
// 不改变原因:数组中的对象的值也没有改变,是因为新创建的变量和原数组中的对象虽然指向同一个地址,但改变的是新变量的值,即新对象的值为2,原数组中的对象还是{num:1}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
上面改变不改变的原因:
核心原理:栈(stack)内存和堆(heap)内存
JS 中的基本数据类型是存在于栈内存中,在栈内存中储存变量名及相应的值。而 Object,Array,Function 存在于堆内存中,栈中储存对象的地址指针,堆内存储存变量名及相应的值
详解: https://www.cnblogs.com/echolun/p/11544045.html (opens new window)
# for-in 和 for-of 区别
for of 循环用来获取一对键值对中的值,而 for in 获取的是 键名
适用场景不同
for of 适用遍历数/数组对象/字符串/map/set 等拥有迭代器对象(iterator)的集合,但是不能遍历对象
for in 更适合遍历对象,当然也可以遍历数组,但是会存在一些问题,
(1)for...in 循环数组是以字符串作为键名“0”、“1”、“2”
(2)特别情况下, for ... in 循环会以看起来任意的顺序遍历键名
# map 和 forEach 区别
- 返回值:
forEach()方法不会返回执行结果,而是 undefined,不可以链式调用。
map()方法会得到一个新的数组并返回,可以与其他方法(如 reduce()、sort()、filter())链接在一起
相同点:
对空数组不会调用回调函数
两种方法都不能用 break 中断,否则会引发异常(不能使用 break 跳出整个循环,不能使用 continue 跳出本次循环)
map 和 forEach 都没有 for 循环快
# js 对象循环
# 1. for in
适用范围:对象
for in 概念:以任意顺序遍历一个对象的除 Symbol 以外的可枚举属性,包括继承的可枚举属性。
for-in 语法:for(keys in zhangsan){}
keys 表示 obj 对象的每一个键值对的键!!所有循环中,需要使用 obj[keys]来取到每一个值!!!
for-in 循环,遍历时不仅能读取对象自身上面的成员属性,也能延续原型链遍历出对象的原型属性
所以,可以使用 hasOwnProperty 判断一个属性是不是对象自身上的属性。
obj.hasOwnProperty(keys)==true 表示这个属性是对象的成员属性,而不是原先属性
使用 for in 也可以遍历数组,但是会存在以下问题:
for in 遍历的是数组的索引(即键名),而 for of 遍历的是数组元素值。
特别情况下, for ... in 循环会以看起来任意的顺序遍历键名
使用 for in 会遍历数组所有的可枚举属性,包括原型属性
index 索引为字符串型数字,不能直接进行几何运算
for in 会遍历手动添加的其他键
var obj = { "0": "a", "1": "b", "2": "c" };
for (var i in obj) {
console.log(i, ":", obj[i]);
}
2
3
4
5
# 2. Object.keys()
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性).
var obj = { "0": "a", "1": "b", "2": "c" };
Object.keys(obj).forEach(function(key) {
console.log(key, obj[key]);
});
2
3
4
5
# 3. Object.getOwnPropertyNames
返回一个数组,包含对象自身的(不含继承的)所有属性(不含 Symbol 属性,但是包括不可枚举属性)
var obj = { "0": "a", "1": "b", "2": "c" };
Object.getOwnPropertyNames(obj).forEach(function(key) {
console.log(key, obj[key]);
});
2
3
4
# 4. Reflect.ownKeys
返回一个数组,包含对象自身的所有属性,不管属性名是 Symbol 或字符串,也不管是否可枚举.但不包括继承自原型的属性
var obj = { "0": "a", "1": "b", "2": "c" };
Reflect.ownKeys(obj).forEach(function(key) {
console.log(key, obj[key]);
});
2
3
4
# Object.keys 和 for in 区别
Object.keys()不会走原型链,而 for in 会走原型链;
Object.keys()会返回一个数组,而 for in 无返回值;
# js Symbol 循环
# 1. Object.getOwnPropertySymbols()
const obj = {};
const foo = Symbol("foo");
obj[foo] = "bar";
for (let i in obj) {
console.log(i); // 无输出
}
Object.getOwnPropertyNames(obj); // []
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]
2
3
4
5
6
7
8
9
10
11
# 2. Reflect.ownKeys
Reflect.ownKeys()方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
返回一个数组,
let obj = {
[Symbol("my_key")]: 1,
enum: 2,
nonEnum: 3,
};
Reflect.ownKeys(obj);
// ["enum", "nonEnum", Symbol(my_key)]
2
3
4
5
6
7
8