for in
for in循环会遍历对象的所有可枚举属性,包括原型链上的属性。这些属性是对象的键(数组的索引),这些键通常是字符串类型,或者是可以转化为字符串的类型。
Symbol类型的属性不会被for in遍历 Symbol的值都是唯一的,不会和其他属性冲突,Symbol设计初衷为了解决属性冲突和名称冲突的问题,使得对象的属性能够有更好的唯一性。
可以转换成字符串的类型
JavaScript 中可以转换为字符串的类型包括:
原始字符串类型 (string)
数字 (number)
布尔值 (boolean)
null 和 undefined
对象(通过 .toString() 方法)
数组(通过 .toString() 方法)
Symbol(通过 String() 转换)
BigInt(通过 String() 转换)
这些类型可以通过隐式或显式的方式转化为字符串。
for in 的用法
const arr=[1,2,3,4,5,6,7,8,9,10];
const str={'hello':1,'world':2,'zhang':3,'san':4};
for(let item in str){
console.log('for in str',item);
}
for(let item in arr){
console.log('for in arr',item);
}
for in遍历的是数组的索引和对象的key值。
let myObject = {
name: "John",
[Symbol('id')]: 123, // Symbol属性
[Symbol('age')]: 30 // 另一个Symbol属性
};
for (let key in myObject) {
console.log(key); // 不会输出Symbol('id')和Symbol('age')
}
for in不会遍历Symbol键,如果需要遍历Symbol键,可以使用Object.getOwnPropertySymbols()方法。
let myObject = {
name: "John",
[Symbol('id')]: 123, // Symbol属性
[Symbol('age')]: 30 // 另一个Symbol属性
};
// 获取所有Symbol类型的属性键
let symbols = Object.getOwnPropertySymbols(myObject);
// 遍历所有Symbol键
symbols.forEach(symbol => {
console.log(symbol, myObject[symbol]);
});
for-in会遍历对象的所有可枚举属性,包括从原型链继承的属性,除非使用hasOwnProperty()方法来过滤掉继承的属性。
const str = {'hello': 1, 'world': 2, 'zhang': 3, 'san': 4};
for (let key in str) {
if (str.hasOwnProperty(key)) { // 检查是否是对象自身的属性
console.log(key, str[key]);
}
}
for in遍历数组存在的问题
for in遍历数组的遍历顺序可能不是按照实际数组的内部顺序。
const arr=[1,2,3,4,5,6,7,8,9,10];
for (let index in arr) {
let res = index + 1;
console.log(res);
}
for-in遍历的是对象属性名的顺序,数组的索引是按照字符串排列的,数组的索引是数字但是会被转换成字符串,所以for-in遍历数组的顺序是按照字符串的顺序排列的,而不是按照实际的数组顺序排列的。
for of
for of 是ES6新增的语法,用来遍历可迭代对象的值序列,,例如Array、String、TypedArray、Map、Set、NodeList、arguments对象、DOM NodeList、由生成器函数生成的生成器、用户定义的可迭代对象等。
for of遍历细节
for of循环迭代一个可迭代对象时,它首先调用可迭代对象的Symbol.iterator()方法,然后使用返回的迭代器对象的next()方法获取每个值,直到迭代器对象的next()方法返回一个done属性为true的对象为止。
let arr = [1, 2, 3, 4, 5];
for (let item of arr) {
console.log(item);
}
输出结果为:12345
for of 的用法
const arr=[1,2,3,4,5,6,7,8,9,10];
const str={'hello':1,'world':2,'zhang':3,'san':4};
for(let item of arr){
console.log('for of arr',item);
}
for(let item of str){
console.log('for of str',item);
}
for of遍历的是数组的值和对象的值,普通对象不能遍历的原因是只有实现Symbol.iterator方法的对象才是可迭代的,而普通对象没有这个属性,所以不能使用for of遍历。
实现迭代器
const str = {
'hello': 1,
'world': 2,
'zhang': 3,
'san': 4,
// 实现 Symbol.iterator
[Symbol.iterator]: function() {
let keys = Object.keys(this); // 获取对象的所有键
let index = 0; // 迭代的初始索引
// 返回迭代器对象
return {
next: () => {
if (index < keys.length) {
const key = keys[index++];
return { value: [key, this[key]], done: false }; // 返回键值对
} else {
return { done: true }; // 完成遍历
}
}
};
}
};
// 使用 for...of 遍历
for (let [key, value] of str) {
console.log(key, value);
}
输出结果:
hello 1
world 2
zhang 3
san 4
总结
for-in和for-of都是遍历对象属性的,但是for-in遍历的是数组的索引和对象的key值,继承自原型链的属性值也会遍历到,for-of遍历的是数组和对象的值。 for-in遍历数组的顺序是按照数组索引转换成字符串的顺序排列的,而不是按照实际的数组顺序排列的。
使用建议
只需要键不关心值可以使用for in来遍历对象的可枚举属性(键) 按顺序遍历数组或者字符串可以使用for of遍历可迭代对象(数组、字符串、Set、Map等) 对于数组,建议使用for of或for Each而不是for-in,以确保数组的顺序遍历元素。