for...in 和 for...of有什么区别
for…in 和 for…of有什么区别
for…in
1.遍历数组
const arr = ["element1", "element2", "element3"]
for (const item in arr) {
console.log("🚀 ~ for in", arr[item])
}
// 输出 element1 element2 element32.遍历对象
const obj = {
name: "obj",
age: 18,
}
for (const item in obj) {
console.log("🚀 ~ for in", item, obj[item])
}
// 输出:
// name obj
// age 18检测是否可枚举
console.log("🚀 ~ ", Object.getOwnPropertyDescriptor(obj, "name")) // 输出: // { value: 'obj', writable: true, enumerable: true, configurable: true } // enumerable: true 可枚举
3.遍历字符串
const str = "hello!world"
for (const item in str) {
console.log("🚀 ~ for in", str[item])
}
// 输出:
// h e l l o ! w o r l d4.遍历字符串,包含unicode字符
const str2 = "a𠮷c"
for (const item in str2) {
console.log("🚀 ~ for in", str2[item])
}
// 输出:
// a � � c5.遍历对象,父类属性也会遍历出来
const fatter = {
fatherAttr: 1
}
const instance = Object.create(fatter)
instance.a = 1;
instance.b = 2;
instance.c = 3;
for (const attr in instance) {
console.log(attr, instance[attr])
}
// 输出:
// a 1
// b 2
// c 3
// fatherAttr 1
// 将原型链上的属性也遍历出来了
// 通过 hasOwnProperty 判断是否是自身属性
for (const attr in instance) {
if (instance.hasOwnProperty(attr)) {
console.log(attr, instance[attr])
}
}for…of
示例:
let str = 'a𠮷c';
for (const item of str) {
console.log(item)
}
// 输出:
// a 𠮷 c遍历Map
const map = new Map([["a", 1], ["b", 2], ["c", 3]]);
for (const mapElement of map) {
console.log(mapElement)
}
// 输出:
// [ 'a', 1 ] [ 'b', 2 ] [ 'c', 3 ]
// 可解构
for (const [key, value] of map) {
console.log(key, value)
}
// 输出:
// a 1 b 2 c 3Set和Array
entries()、keys()、values()都返回一个迭代器对象entries()返回值为集合的键值对[[key, value], [key, value], [key, value]](对于数组,key 就是索引值;对于 Set,key 就是 value)keys()返回值为集合的键名[key, key, key](对于数组,key 就是索引值;对于 Set,key 就是 value)values()返回值为集合的值[value, value, value]
const arr2 = ["a", "b", "c"];
let set = new Set(arr2);
// 1.entries
for (const entry of set.entries()) {
console.log(entry, "entries")
}
// 输出:
// [ 'a', 'a' ] [ 'b', 'b' ] [ 'c', 'c' ]
for (const arElement of arr2.entries()) {
console.log(arElement, "arElement")
}
// 输出:
// [ 0, 'a' ] [ 1, 'b' ] [ 2, 'c' ]
// 2.keys
for (const key of set.keys()) {
console.log(key, "keys")
}
// 输出:
// a b c
for (const key of arr2.keys()) {
console.log(key, "keys")
}
// 输出:
// 0 1 2
// 3.values
for (const value of set.values()) {
console.log(value, "values")
}
// 输出:
// a b c
for (const value of arr2.values()) {
console.log(value, "values")
}
// 输出:
// a b cfor...in 和 for...of 的区别
| for…in | for…of | |
|---|---|---|
| key | value | 结果 |
| 可枚举属性 | 可迭代对象 | 遍历 |
| 遍历对象 | 遍历数组 | 常用 |
拓展操作
const father = {
fatherAttr: 1
}
const instance = Object.create(father)
instance.a = 1;
instance.b = 2;
instance.c = 3;
Object.defineProperty(instance, "d", {
value: 4,
enumerable: false, // 不可枚举
})1.Object.Keys 获取键名数组
for (const key of Object.keys(instance)) {
console.log(key, "Object.keys")
}
// 输出:
// a b c
Object.keys不会遍历原型链上的属性、以及自身不可枚举的属性
Object.keys返回的是一个数组,所以可以使用数组的方法
- ps:
Object.keys与for in的区别for (const instanceKey in instance) { console.log(instanceKey, "for in") } // 输出: // a b c fatherAttrfor in会遍历原型链上的属性,但是同样不会遍历自身不可枚举的属性
2.Object.getOwnPropertyNames() 获取键名数组
Object.getOwnPropertyNames() 与 Object.keys() 的区别在于,Object.getOwnPropertyNames() 会遍历自身不可枚举的属性
for (const instanceKey of Object.getOwnPropertyNames(instance)) {
console.log(instanceKey, "Object.getOwnPropertyNames")
}
// 输出:
// a b c d3.Object.entries() 获取键值对数组
Object.entries()不会遍历原型链上的属性和自身不可枚举的属性
for (const instanceKey of Object.entries(instance)) {
console.log(instanceKey, "Object.entries")
}
// 输出:
// [ 'a', 1 ] [ 'b', 2 ] [ 'c', 3 ]- ps: 当使用对象初始化一个Map实例,可以使用
Object.entries()来初始化const obj = {a: 1, b: 2, c: 3}; const map = new Map(Object.entries(obj)); console.log(map.get("a")) // 1
4.Object.values() 获取对象的属性值数组
Object.values()不会遍历原型链上的属性和自身不可枚举的属性
for (const instanceKey of Object.values(instance)) {
console.log(instanceKey, "Object.values")
}
// 输出:
// 1 2 35.Object.getOwnPropertySymbols()获取Symbol属性名
上面的方法都无法获取Symbol属性名,只能通过
Object.getOwnPropertySymbols()来获取
instance[Symbol("e")] = 5;
for (const instanceKey of Object.getOwnPropertySymbols(instance)) {
console.log(instanceKey, "Object.getOwnPropertySymbols")
}
// 输出:
// Symbol(e){% referfrom 1,'JavaScript骚操作之遍历、枚举与迭代(上篇)','https://juejin.cn/post/6844903724897271816' %}
什么是可枚举数据呢?
举个例子来说
const obj = { x: 100 }我们使用 Object.getOwnPropertyDescriptors 方法获取指定对象所有的自有属性的属性描述符。

这时候发现他的每一个属性中 enumerable 都是 true,这时候他就是可枚举的。
如果一个属性的enumerable为false,下面三个操作不会取到该属性。
for..in循环
Object.keys方法
JSON.stringify方法
所以一般情况下 对象、数组、字符串都是可枚举的
什么是可迭代数据呢?
for...of用于可迭代的数据,如:
- 数组
- 字符串
- Map
- Set
const arr = [1, 2, 3]数组中有个 Symbol.iterator的属性:
- 1.只要一个数据已经实现了Iterator接口, 那么这个数据就有一个叫做
[Symbol.iterator]的属性 - 2.
[Symbol.iterator]的属性会返回一个函数 - 3.
[Symbol.iterator]返回的函数执行之后会返回一个对象 - 4.
[Symbol.iterator]函数返回的对象中又一个名称叫做next的方法 - 5.next方法每次执行都会返回一个对象
{value: 1, done: false} - 6.这个对象中存储了当前取出的数据和是否取完了的标记

就类似设计模式中的迭代器模式:
不断有next、next去调用:
- A next() => B
- B next() => C
- 如此 如此
了解了上面的情况之后,我们也可以理解什么时候用 for...of 什么时候用 for...in?
- for...in可以用在可枚举的数据
- for...of用于可迭代的数据
{% referfrom 2,'for...in 和 for...of有什么区别','https://juejin.cn/post/7104444342684614664' %}