IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> [js基础]for in、for of、拓展运算符 -> 正文阅读

[JavaScript知识库][js基础]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 = [1, 2, 3, 4]
let str = "1234"
let set = new Set([1, 2, 3, 4])

console.log(arr)
console.log(new String(str)) // 使用对象方法包装一下
console.log(set)

img

img

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

let arr = [1, 2, 3, 4]
let iter = arr[Symbol.iterator]()

img

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

二、for in的原理

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

2.1 注意点1

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

let a = [1, 2, 3, 4]
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 = [1, 2, 3, 4]
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 = [1, 2, 3, 4]
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 ={ 
    age: 18,
    sleep: function(){}
};
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 = {
    0: 1,
    1: 2,
    2: 3,
    3: 4,
    length: 4
}

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 = {
    0: 1,
    1: 2,
    2: 3,
    3: 4,
    length: 4,

    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 = {    0: 1,    1: 2,    2: 3,    3: 4,    length: 4,    [Symbol.iterator]() {        // 过滤掉非number索引的item        let arr = Object.values(JSON.parse(JSON.stringify(obj, replacer))),            index = 0,            len = arr.length        return {            next: function () {                if (index < len) {                    return {                        value: arr[index++],                        done: false                    }                } else {                    return {                        value: undefined,                        done: true                    }                }            }        }    },    myFunc02() {        console.log('2');    }}for (let i = 0; i < obj.length; i++) {    console.log(obj[i])}// 1 2 3 4for (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 = [1, 2, 3, 4]
function test(...args) {
    console.log(args)
}
test(1, 2, 3, 4)  //  [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 = {
    0: 1,
    1: 2,
    2: 3,
    3: 4,
    length: 4,
    [Symbol.iterator]() {
        // 过滤掉非number索引的item
        let arr = Object.values(JSON.parse(JSON.stringify(obj, replacer))),
            index = 0,
            len = arr.length

        return {
            next: function () {
                if (index < len) {
                    return {
                        value: arr[index++],
                        done: false
                    }
                } else {
                    return {
                        value: undefined,
                        done: true
                    }
                }
            }
        }
    },
    myFunc02() {
        console.log('2');
    }

}

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

console.log(...obj)  // 1 2 3 4
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-23 12:15:16  更:2021-11-23 12:17:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 2:01:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码