javascript中的遍历

160 阅读5分钟

for循环

  • 只用于遍历数组,书写麻烦
    let arr = ['a', 'b', 'c']
    for (let i = 0,len = arr.length;i < len;i++) {
        console.log(i)
    }

forEach循环

  • 数组内置方法,不能中途跳出循环,break(SyntaxError: Illegal break statement)和return都无效
    let arr = ['a', 'b', 'c']
    arr.forEach(item => {
        console.log(item)
    })

for...in

  • 遍历对象(数组也是对象)及其原型链可枚举属性

    (Object.keys(obj)仅遍历对象自身,不遍历原型链)

  • 遍历键名,为字符串类型(遍历数组时为数组下标,返回仍为字符串类型)
  • 对象的键名存为数字字符串时会出现顺序不一致,原因在于for...in遍历顺序为:**先按照升序遍历出整数属性,然后其他属性按照创建时候的顺序遍历出来。**所谓整数属性,即String(Math.trunc(Number(prop)) === prop,Math.trunc去除小数部分参考链接,负数的话当作字符串处理.....
Array.prototype.getLength = function() {
    return this.length;
};
var arr = ['a', 'b', 'c'];
arr.name = 'June';
Object.defineProperty(arr, 'age', {
    enumerable: true,
    value: 17,
    writable: true,
    configurable: true
});
console.log(Object.keys(arr)) // ["0", "1", "2", "name", "age"]
for(var i in arr) {
    console.log(typeof(i)) // string string string string string string
    console.log(i); // 0,1,2,name,age,getLength
}
let codes = {
  "49": "Germany",
  "41": "Switzerland",
  "44": "Great Britain",
  "1": "USA"
};

for(let code in codes) {
  console.log(code); // 1, 41, 44, 49
}

不推荐在数组中使用for...in遍历

for..of

  • 修复了forEach和for...of的缺点同时提供了所有数据结构的统一操作接口
  • 遍历值为键值,通过Object.keys() Object.entries()来获取索引
  • 不支持遍历普通对象 Uncaught TypeError: obj is not iterable普通对象没有迭代器

数组空项:['a',,'c']只有 forEach 和 for...in 遍历会跳过空值,其他会解析为 undefined,因此建议使用for...of 或for循环,因为JSON.parse('["a", , "c"]')会报错

在写javascript中的遍历这篇时深冻结用到的Object.getOwnPropertyNames(),然后又把遍历看了一遍,整理一下,发现之前写的这篇不够细.来补充下

对象遍历

  • Object.getOwnPropertyNames(obj) 对象自身 除Symbol之外的 可枚举+不可枚举属性 的数组
  • **Object.getOwnPropertySymbols(obj)**对象自身 Symbol 属性的数组
  • **Object.keys()**对象自身 除Symbol之外的 可枚举属性 (非对象参数会被转为对象)
  • for...in对象自身+继承 除Symbol之外的 可枚举属性
  • **Reflect.ownKeys()**对象自身 所有属性(可枚举+不可枚举,非Symbol+Symbol),参数不是对象会报错TypeError等同于Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target))。
// 对象自身 可枚举 字符类型 name
// 对象自身 不可枚举 字符类型 age
// 对象自身 可枚举 Symbol类型 
// 对象自身 不可枚举 Symbol类型 
// 原型对象 可枚举 字符类型 protoProperty
// 原型对象 可枚举 Symbol类型 protosymbolproperty
// 原型对象 不可枚举 字符类型 protoUnenmerProto
// 原型对象 不可枚举 Symbol类型

// obj对象属性定义
var obj = { 'name': 'Poly'}
obj[Symbol()] = 'objsymbolproperty'
Object.defineProperty(obj, 'age', { value: '18', enumerable: false })
Object.defineProperty(obj, Symbol(), { value: 'symbol', enumerable: false })

// 原型对象属性定义
Object.prototype.protoProperty = 2
Object.prototype[Symbol()] = 'protosymbolproperty'
Object.defineProperty(Object.prototype, 'protoUnenmerProto', { value: 'protoUnenmerProto', enumerable: false })
Object.defineProperty(Object.prototype, Symbol(), { value: 'protosymbol', enumerable: false })

// 不同的遍历方法
console.log('Object.getOwnPropertyNames')
console.log(Object.getOwnPropertyNames(obj)) //  ["name", "age"]

console.log('Object.getOwnPropertySymbols')
console.log(Object.getOwnPropertySymbols(obj)) //  [Symbol(), Symbol()]

console.log('Reflect.ownKeys')
console.log(Reflect.ownKeys(obj))	// ["name", "age", Symbol(), Symbol()]

console.log("For in")
for (var a in obj) {
	console.log(a)	// name protoProperty
}

console.log('Object.keys')
console.log(Object.keys(obj)) // ["name"]

// 报错 因为对象没有Iterator接口
console.log('For of')
for (var a of obj) {
	console.log(a)
}

// 顺序
// 数字类型|数字字符串类型 (数字升序) > 字符串类型,Symbol类型(插入顺序)
var test = {'45': 45, '0': 0, 2: 2, '-2': '-2'} // undefined
test // {0: 0, 2: 2, 45: 45, -2: "-2"}

总结:Object的静态方法遍历的都只是对象自身的属性!

数组遍历

  • for循环 使用无语句的 for一定要使用分号 如果没有分号,循环声明之后的行将被视为循环语句。很坑的分号与for循环的问题哈哈
  • forEach
    • 无法中断,break和return都无法中断
    • forEach() 不会在迭代之前创建数组的副本
    • promise 或 async会存在问题??
  • For...in 遍历的是属性名,数组是特殊的对象
  • For...of 遍历的是属性值
var arr = ['0','1', ,'3', undefined, null, 6, '', 8]

console.log('for循环')
for (let i = 0;i < arr.length;i++) {
	console.log(arr[i]) // 0 1 undefined 3 undefined null 6   8
}

console.log('forEach')
arr.forEach((item, index) => {
	console.log(item) // // 0 1 3 undefined null 6   8
})

console.log('for in')
for(let index in arr) {
	console.log(arr[index]) // 0 1 3 undefined null 6   8
}

console.log('for of')
for(let item of arr) {
	console.log(item) // 0 1 undefined 3 undefined null 6   8
}

总结: forEach,for...in会跳过无效项

遍历中断

  • forEach Uncaught SyntaxError: Illegal break statement语法报错不能退出循环
  • for循环,for...in,for...of可以退出,按预期执行

遍历值

  • for循环和for...in遍历键名即key,数组中更习惯称为index
  • for...of遍历键值即value
  • forEach遍历的回调函数第一项是键值value,第二项是键名index

for..of..循环扩展

实际上是依次将迭代器(或任何可迭代的对象,如生成器函数)的值赋予指定变量并进行循环的语法,当对象没有默认迭代器的时候,当然不可以进行循环,而通过给对象增加一个默认迭代器,即[Symbol.iterator]属性,就可以实现for..of..循环,实际上是依次将迭代器(或任何可迭代的对象,如生成器函数)的值赋予指定变量并进行循环的语法,当对象没有默认迭代器的时候,当然不可以进行循环,而通过给对象增加一个默认迭代器,即[Symbol.iterator]属性,就可以实现

Object.prototype[Symbol.iterator] = function *keys(){
  for(let n of Object.keys(this)){ // 此处使用Object.keys获取可枚举的所有属性
    yield n
  }
}

最后给自己挖个坑,vuev-for的源码