[js基础]for in、for of、拓展运算符

弄懂for in、for of、可迭代对象

for of是ES6新增的循环方法,因为for in在遍历数组时,有很多不足之处,现在通常都使用for of来遍历数组。遍历总是看上去很简单,但深究下来,又会牵扯到键值对,原型链,可枚举属性,迭代器接口,Symbol一系列内容,所以本文将一次弄清楚这里面的关系。

当然,在写普通业务时,记得取key用for in,取value用for of,一般是不会出岔子的(吧)?!

一、可迭代对象

迭代器是很基础的数据结构,一般来说,一个标准的迭代器解构会提供一个next()方法,返回值结构如下:

  • value:本次迭代拿到的值
  • done:一个标识符

并不是说定义了一个Object,就能对它进行遍历,从Object到Array之间,封装了一个迭代器接口。

let arr = [1234]
let str = "1234"
let set = new Set([1, 2, 3, 4])

console.log(arr)
console.log(new String(str)) // 使用对象方法包装一下
console.log(set)
[js基础]for in、for of、拓展运算符
img
[js基础]for in、for of、拓展运算符
img

显而易见,Symbol(Symbol.iterator): ƒ values()是一个迭代器接口,打印观察之。

let arr = [1234]
let iter = arr[Symbol.iterator]()
[js基础]for in、for of、拓展运算符
img

细究来,无非就是数据结构的基础知识迭代器嘛,这里就不展开了,至于可枚举属性,你只要知道,true是能被遍历到,false是不能,其他的就暂时不管了。

二、for in的原理

简单来说,for in的作用就是:遍历自身继承可枚举属性。

2.1 注意点1

使用 for in 循环遍历对象的属性时,原型链上的所有属性都将被访问

let a = [1234]
for(let i in a){
 console.log(a);
}
打印结果:0 1 2 3
// 在原型链上的Object上自定义一个myFunc方法
Object.prototype.myFunc01 = function ({
    console.log('1');
}

// 在原型链上的Array上自定义一个myFunc方法
Array.prototype.myFunc02 = function (value{
   console.log('2');
}

let b = [1234]
for (let i in b) {
    console.log(i);
}

打印结果:0 1 2 3 myFunc02 myFunc01

2.2 注意点2

只遍历对象自身的属性,而不遍历继承于原型链上的属性,应使用hasOwnProperty 方法过滤。

// 在原型链上的Object上自定义一个myFunc方法
Object.prototype.myFunc01 = function ({
    console.log('1');
}

// 在原型链上的Array上自定义一个myFunc方法
Array.prototype.myFunc02 = function (value{
   console.log('2');
}

let b = [1234]
for (let key in b) {
    if(b.hasOwnProperty(key)){
        console.log(key);
    }
}
打印结果:0 1 2 3

对于使用for in可能导出的bug,有两种方式避免

1.在循环数组集合时,不使用for-in,统一使用for(let i=0;i<length;i++)这种形式;

2.在for in循环中增加一个hasOwnProperty的判断。

2.3 对比Object.keys()

for in的作用和Object.keys()方法特别像,Object.keys() 方法会返回一个由给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for  in 循环遍历该对象时返回的顺序一致。

两者的主要区别是for in 循环还会枚举其原型链上的属性,返回值是这个对象的所有可枚举属性组成的字符串数组。

Object.prototype.say=function(){};
let person ={ 
    age18,
    sleepfunction(){}
};
console.log(Object.keys(person));  //结果  ["age", "sleep"] 
// for in 结果:["age", "sleep", "say"] 

小技巧:

  • object对象没有length属性,可以通过Object.keys(person).length,来获取person的长度。

  • index索引为字符串型数字,不能直接进行几何运算

  • 遍历顺序有可能不是按照实际数组的内部顺序

  • 使用for in会遍历数组所有的可枚举属性,包括原型。例如上栗的原型方法method和name属性

三、for of的原理

  • for of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象的集合。但是不能遍历对象,因为没有迭代器对象,与forEach()不同的是,它可以正确响应break、continue和return语句。
  • for of循环不支持普通对象,但如果想迭代一个对象的属性,可以用for in循环(这也是它的本职工作)或内置的Object.keys()方法。

那么如果自己定义一个对象,将其仿写成一个数组,用for of遍历它会怎么样呢?

// 定义一个对象,仿写成一个数组  
let obj = {
    01,
    12,
    23,
    34,
    length4
}

for(let i in obj){
    console.log(i)
}
//打印:0 1 2 3 length

for(let i of obj){
    console.log(i)
}
// 报错 Uncaught TypeError: obj is not iterable

显然,for of对迭代器接口有所要求,普通对象是无法使用for of遍历的。

3.1 考点1

如果说,要实现过滤非数字键值呢,怎么做呢?思路很简单,JSON.stringify利用一下就可。

为什么会提这个问题,是为了下一个考察点做铺垫。

// 定义一个对象,仿写成一个“数组”  
let obj = {
    01,
    12,
    23,
    34,
    length4,

    myFunc02() {
        console.log('2');
    }

}

let obj1 = JSON.stringify(obj)
console.log(obj1)
// {"0":1,"1":2,"2":3,"3":4,"length":4}

let replacer = function (key, value{
    // 如果key不是数字,则过滤掉这个值
    if (isNaN(+key)) {
        return undefined
    }
    return value
}
let obj2 = JSON.stringify(obj, replacer)
console.log(obj2);
// {"0":1,"1":2,"2":3,"3":4}

3.2 考点2

如果面试官问你,怎么实现让一个普通obj能够让for of遍历,你该怎么做?这里就不细说了,相信懂的人看一遍代码也能马上明白。

// stringify过滤函数
let replacer = function (key, value{
    // 如果key不是数字,则过滤掉这个值
    if (isNaN(+key)) {
        return undefined
    }
    return value
}
Object.prototype.myFunc01 = function ({
    console.log('1');
}

// 定义一个对象,仿写成一个数组  
let obj = {
    01,
    12,
    23,
    34,
    length4,
    [Symbol.iterator]() {
        // 过滤掉非number索引的item
        let arr = Object.values(JSON.parse(JSON.stringify(obj, replacer))),
            index = 0,
            len = arr.length

        return {
            nextfunction ({
                if (index < len) {
                    return {
                        value: arr[index++],
                        donefalse
                    }
                } else {
                    return {
                        valueundefined,
                        donetrue
                    }
                }
            }
        }
    },
    myFunc02() {
        console.log('2');
    }

}

for (let i = 0; i < obj.length; i++) {
    console.log(obj[i])
}
// 1 2 3 4

for (let i of obj) {
    console.log(i)
}
// 1 2 3 4

四、for in和for of的区别

小结一下。

  • for of无法循环遍历对象

  • 遍历输出结果不同

    for in循环遍历的是数组的键值(索引),而for of循环遍历的是数组的值。

  • for in 会遍历原型链上的所有属性,for of不会

五、补充:拓展运算符的遍历原理

…(拓展运算符 | 展开运算符) 也是es6的语法,能用for of遍历的,用…也能进行拓展运算。

5.1 例子1

let arr = [1234]
function test(...args{
    console.log(args)
}
test(1234)  //  [1, 2, 3, 4]
test(...arr)  //  [1, 2, 3, 4]
// 即...[1, 2, 3, 4] = 1,2,3,4
for(let i of arr){
    console.log(i) // 1 2 3 4
}

5.2 例子2

// stringify过滤函数
let replacer = function (key, value{
    // 如果key不是数字,则过滤掉这个值
    if (isNaN(+key)) {
        return undefined
    }
    return value
}
Object.prototype.myFunc01 = function ({
    console.log('1');
}

// 定义一个对象,仿写成一个数组  
let obj = {
    01,
    12,
    23,
    34,
    length4,
    [Symbol.iterator]() {
        // 过滤掉非number索引的item
        let arr = Object.values(JSON.parse(JSON.stringify(obj, replacer))),
            index = 0,
            len = arr.length

        return {
            nextfunction ({
                if (index < len) {
                    return {
                        value: arr[index++],
                        donefalse
                    }
                } else {
                    return {
                        valueundefined,
                        donetrue
                    }
                }
            }
        }
    },
    myFunc02() {
        console.log('2');
    }

}

for (let i of obj) {
    console.log(i)
}
// 1 2 3 4

console.log(...obj)  // 1 2 3 4


原文始发于微信公众号(豆子前端):[js基础]for in、for of、拓展运算符

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/56667.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!