数组遍历和对象遍历

数组遍历

1. arr.forEach(callback(currentVal [, index [,array]] ) [,thisArg] )

  • callback含有三个参数: 当前值、当前索引、目标数组
  • thisArg — callback中的this指向
  • return false;终止本次循环,继续下一个;
  • 抛出异常;可以跳出整个循环
    遍历数组中的所有值并忽略回调函数的返回值。
    2. arr.every(...)
    如果有一个不满足条件,中止循环,直接返回false; 全部满足返回true;
    3. arr.some(...)
    如果有一个满足条件,中止循环,直接返回true; 全部不满足返回false;
    4. for...in
    遍历的是数组的下标(索引)以及自定义的可枚举属性。
var obj = {a: 2, b: 4};
for(var k in obj){
  console.log(obj[k])
}

数组使用for...in遍历时的缺点:
(1) 数组的键名是数字,但是for...in循环是以字符串作为键名“0”、“1”、“2”等等。
(2)for...in循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。
(3) 某些情况下,for...in循环会以任意顺序遍历键名。
所以for...in主要适用于对象

5. for循环
遍历数组的下标值

6. for...of(ES6新增)
遍历数组的值。

let arr = [1,2,3];
arr.foo = "hello";
for(let i of arr){
  console.log(i)  // 1,2,3    数组的遍历器接口只返回具有数字索引的属性,不会返回数组的foo属性
}
//  for...in 遍历的是数组的所有可枚举属性
for(let index in arr){
  console.log(index)   // 0,1,2,foo
}

原理:for...of首先会向目标对象请求一个迭代器对象(遍历器对象),调用迭代器对象的next()方法来遍历所有返回值。
意味着for...of的目标对象必须具有Iterator接口,JS中具有Iterator接口的数据结构:数组(Array)、类数组对象(函数中的arguments 、DOM NodeList 对象)、String、Map和Set结构 、 Generator 对象
数组有内置的@@iterator,我们使用内置的@@iterator来手动遍历数组,看看是如何工作的?

var arr = ["zhangsan","lisi","wangwu","h"];
for(let val of arr){
     console.log(val) //依次打印出值 
}


var _iterator = arr[Symbol.iterator]();   // _iterator即为迭代器对象
console.log(_iterator.next()) //  {"value":"zhangsan","done":false}
console.log(_iterator.next()) //  {"value":"lisi","done":false}
console.log(_iterator.next()) //  {"value":"wangwu","done":false}
console.log(_iterator.next()) //  {"value":"h","done":false}
console.log(_iterator.next()) //  {"done":true}

如果一个自定义对象不在上述结构中,想使用for..of,那么可以为对象手动添加Iterator接口,直白讲就是添加Symbol.iterator属性,返回一个迭代器对象(就是for...of访问的),对象中要有一个next()方法,返回一个具有value和done属性的对象{value: ...,done:...}

{
    let myObj = {
        data: ["zhangsan","lisi"],
        [Symbol.iterator]() {
            let index = 0;
            let next = function() {
                if(index < this.data.length){
                    return  {value: this.data[index++], done: false }  
                }
                return { value: undefined, done: true}
            }
            // 返回迭代器对象(遍历器对象)
            return {
            //  必须具有next() 方法
                next: next.bind(this)
            }
           
        }
    }

    for(let val of myObj){
        console.log(val)   // “zhangsan” “lisi”
    }
}

可通过ES6中 Generator生成器快速创建iterator接口

总结:for...of相对于上面那些,具备的优点:
(1) 有着同for...in一样的简洁语法,但是没有for...in那些缺点。
(2) 不同用于forEach方法,它可以与break、continuereturn配合使用。
(3)提供了遍历所有数据结构的统一操作接口。

对象遍历

1. for...in
遍历对象的所有可枚举属性 (包含原型链)
2. Object.keys(obj)
返回数组,包含对象的所有可枚举属性 (不包含原型链)
3. Object.getOwnPropertyNames(...)
返回数组,包含对象的所有属性,无论是否可枚举。(不包含原型链)

扩展:

(1)in操作符和 hasOwnProperty() 检查对象中是否包含某个属性。
无论属性是否枚举,只要存在,都会返回true。区别只在于是否查找原型链

// in 操作符 会检查属性名称是否存在对象及其原型链中 
console.log("b" in myObj) // true
console.log("c" in myObj)  // false
//  hasOwnProperty(...)只会检查属性名称是否在对象自身上
myObj.hasOwnProperty("c")  // false

(2)obj.propertyIsEnumerable(prop) 检查属性prop是否可枚举(不包含原型链)

// 检查属性是否存在于对象中(而不是在原型链上),并满足enumerable: true
obj.propertyIsEnumerable(prop);  //  true || false
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容