• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

JS基础for...in、for...of、forEach()

武飞扬头像
The..Fuir
帮助1

学新通

 学新通

for in循环

for...in 语句以任意顺序遍历一个对象的除 Symbol 以外的可枚举属性。
for...in 循环只遍历可枚举属性。像 Array和 Object 使用内置构造函数所创建的对象都会继承自Object.prototype和String.prototype的不可枚举属性,例如 String 的 indexOf()  方法或 Object的toString()方法。循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性
语法:for (variable in object)    variable:在每次迭代时,variable会被赋值为不同的属性名。 object:非Symbol类型的可枚举属性被迭代的对象。
最好不要用for...in去迭代一个数组。

  1.  
    var obj={a:1,b:2,c:3};
  2.  
    for(var prop in obj){
  3.  
    console.log(prop " " obj[prop]);
  4.  
    }

学新通

 可以循环遍历数组

  1.  
    var arr = ['nick','freddy','mike','james'];
  2.  
     
  3.  
    for(var index in arr){
  4.  
    console.log(index '. ' arr[index]);
  5.  
    }
  6.  
    // 0. nick
  7.  
    // 1. freddy
  8.  
    // 2. mike
  9.  
    // 3. james

for in 与 for of 它们之间的主要区别在于它们的迭代方式

for...in 语句以任意顺序迭代对象的可枚举属性,会遍历手动添加的其他键,甚至包括原型链上的键,只能获得对象的键名,不能直接获取键,为遍历对象而设计。
for...of 语句遍历可迭代对象定义要迭代的数据,允许遍历获得键值,数组的遍历器接口只返回具有数字索引的属性,不同于forEach方法,它可以与break、continue和return配合使用。提供了遍历所有数据结构的统一操作接口。
 

  1.  
    Object.prototype.objCustom = function() {};
  2.  
    Array.prototype.arrCustom = function() {};
  3.  
     
  4.  
    let iterable = [3, 5, 7];
  5.  
    iterable.foo = 'hello';

每个对象将继承objCustom属性,并且作为Array的每个对象将继承arrCustom属性,因为将这些属性添加到Object.prototype和Array.prototype。由于继承和原型链,对象iterable继承属性objCustom和arrCustom。

  1.  
    for (let i in iterable) {
  2.  
    console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
  3.  
    }

此循环仅以原始插入顺序记录iterable 对象的可枚举属性。它不记录数组元素3, 5, 7 或hello,因为这些不是枚举属性。但是它记录了数组索引以及arrCustom和objCustom。

  1.  
    for (let i in iterable) {
  2.  
    if (iterable.hasOwnProperty(i)) {
  3.  
    console.log(i); // 0, 1, 2, "foo"
  4.  
    }
  5.  
    }

这个循环类似于第一个,但是它使用hasOwnProperty() 来检查,如果找到的枚举属性是对象自己的(不是继承的)。如果是,该属性被记录。记录的属性是0, 1, 2和foo,因为它们是自身的属性(不是继承的)。属性arrCustom和objCustom不会被记录,因为它们是继承的。

  1.  
    for (let i of iterable) {
  2.  
    console.log(i); // 3, 5, 7
  3.  
    }

for of循环迭代并记录iterable作为可迭代对象定义的迭代值,这些是数组元素 3, 5, 7,而不是任何对象的属性。

对于对象

对于普通的对象,for...of结构不能直接使用,会报错,必须部署了 Iterator 接口后才能使用。但是,这样情况下,for...in循环依然可以用来遍历键名。

  1.  
    let es6 = {
  2.  
    edition: 6,
  3.  
    committee: "TC39",
  4.  
    standard: "ECMA-262"
  5.  
    };
  6.  
     
  7.  
    for (let e in es6) {
  8.  
    console.log(e);
  9.  
    }
  10.  
    // edition
  11.  
    // committee
  12.  
    // standard
  13.  
     
  14.  
    for (let e of es6) {
  15.  
    console.log(e);
  16.  
    }
  17.  
    // TypeError: es6[Symbol.iterator] is not a function

上面代码表示,对于普通的对象,for...in循环可以遍历键名,for...of循环会报错。

一种解决方法是,使用Object.keys方法将对象的键名生成一个数组,然后遍历这个数组。

  1.  
    for (var key of Object.keys(someObject)) {
  2.  
    console.log(key ': ' someObject[key]);
  3.  
    }

在js中一般使用的循环有两种

1.常规的for(var i=0;i<length;i )

2.for-in:for(var item in list)

但是个人更喜欢使用第一种循环,而不喜欢几乎从来不使用for-in这种写法,原因如下:

1.第一种写法能够很好的控制循环何时结束,以及对应的索引;而第二种循环无法控制

2.第二种写法在某种情况下,可能会导致一些奇怪的bug

针对原因2参见下面简单的案例:

学新通

以上是在jsBin中编辑的代码,在第一段代码中,对js的数组Array添加了一个新的方法(prototype 属性使您有能力向对象添加属性和方法),为了在某些时候能够方便使用。此时,如果用for-in循环出数组arr的内容,会发现在本来想要得到的0,1,2,3的后面会多一个function(){alert("myfunction");},这应该不是我们想要得到的结果。

注意:for..in循环会把某个类型的原型(prototype)中方法与属性给遍历出来,所以这可能会导致代码中出现意外的错误

上面只是简单的遍历一个数组,可能出现的问题还不够明显,如下所示
学新通

如果我们遍历的数组中存放的是业务对象,此时会发现,最后一次输出的是空,在被循环的数组中不存在这个名称为空的人员,此时出现的错误就导致某些业务无法正常使用或显示。

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

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

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

hasOwnProperty函数用于指示一个对象自身(不包括原型链)是否具有指定名称的属性。如果有,返回true,否则返回false

该方法属于Object对象,由于所有的对象都"继承"了Object的对象实例,因此几乎所有的实例对象都可以使用该方法。

学新通

 for in , for of 和forEach三者都是循环时经常使用的,但是每个使用场景都是有轻微不同,接下来就进行一个对比

for…in…的作用

枚举对象

  1.  
    const person = {
  2.  
    name: 'Lydia',
  3.  
    age: 21,
  4.  
    };
  5.  
     
  6.  
    for (const item in person) {
  7.  
    console.log(item);
  8.  
    }

这个输出结果是: name age

对于这个结果可以简单理解为,对于对象object,使用for…in…循环是对对象的key值进行循环

但是使用for…of…结果就不相同

  1.  
    const person = {
  2.  
    name: 'Lydia',
  3.  
    age: 21,
  4.  
    };
  5.  
     
  6.  
    for (const item of person) {
  7.  
    console.log(item);
  8.  
    }

这个输出结果TypeError: person is not iterable

这个结果可以看出for…of…不能对对象进行循环

再看看forEach能怎么样?

  1.  
    const person = {
  2.  
    name: 'Lydia',
  3.  
    age: 21,
  4.  
    }
  5.  
     
  6.  
    person.forEach((i) => {
  7.  
    console.log(i)
  8.  
    })

可枚举数组

这个输出结果为 0 ‘a’ 1 ‘b’ 2 ‘c’

这个结果看出使用for…in…是输出索引值,通过索引值能拿到数组数据

但是使用for…of…结果就不相同

  1.  
    const arr = ['a','b','c']
  2.  
     
  3.  
    for (const item of arr) {
  4.  
    console.log(item);
  5.  
    }

这个输出结果为 ‘a’ ‘b’ ‘c’

这个结果看出使用for…of…是输出数组值

  1.  
    const arr = ['a','b','c']
  2.  
     
  3.  
    for (const item of arr) {
  4.  
    console.log(item);
  5.  
    }

可枚举数组的原型对象

  1.  
    Array.prototype.sayHello = function(){
  2.  
    console.log("Hello")
  3.  
    }
  4.  
    Array.prototype.str = 'world';
  5.  
    var myArray = [1,2,3];
  6.  
    myArray.name='数组';
  7.  
     
  8.  
    for(let index in myArray){
  9.  
    console.log(index);
  10.  
    }

这个输出结果是: 0 1 2 name sayHello str

这个结果看出for in 不仅返回的是数组的下标,而且将数组的原型对象以及数组对象本身属性值都会返回。但是这也存在一个问题,在实际工作开发中,这些对象很可能是不需要的,全部列举出来可能会产生新的问题。

为了解决原型对象这个问题,可以使用hasOwnProperty
 

  1.  
    Array.prototype.sayHello = function(){
  2.  
    console.log("Hello")
  3.  
    }
  4.  
    Array.prototype.str = 'world';
  5.  
    var myArray = [1,2,3];
  6.  
    myArray.name='数组';
  7.  
     
  8.  
    for(let index in myArray){
  9.  
    if(myArray.hasOwnProperty(index)) {
  10.  
    console.log(index);
  11.  
    }
  12.  
    }

forEach的作用

可遍历数组

  1.  
    Array.prototype.sayHello = function(){
  2.  
    console.log("Hello")
  3.  
    }
  4.  
    Array.prototype.str = 'world';
  5.  
    var myArray = ['a','b','c'];
  6.  
    myArray.name='数组';
  7.  
     
  8.  
    myArray.forEach((value,i) => {
  9.  
    console.log(value)
  10.  
    console.log(i)
  11.  
    })

无法break

forEach有个问题就是不能中断执行

  1.  
    var arr = [3, 5, 7];
  2.  
     
  3.  
    arr.forEach(function (value) {
  4.  
    console.log(value);
  5.  
    if (value === 5) {
  6.  
    return false;
  7.  
    }
  8.  
    });

输出的结果是 3 5 7

从结果可以看出,return false没有执行,他会一直运行到底

但是 for in 可以用break :

  1.  
    var arr = [3, 5, 7];
  2.  
     
  3.  
    for (let index in arr) {
  4.  
    console.log(arr[index]);
  5.  
    if (arr[index] == 5) {
  6.  
    break;
  7.  
    }
  8.  
    }

输出的结果是 3 5

从结果可以看出,for in 可以使用break

for…of…的作用

可遍历数组

针对上面1.1.3中提及的问题,除了可用forEach,还可以使用for of进行处理

  1.  
    Array.prototype.sayHello = function(){
  2.  
    console.log("Hello")
  3.  
    }
  4.  
    Array.prototype.str = 'world';
  5.  
    var myArray = ['a','b','c'];
  6.  
    myArray.name='数组';
  7.  
     
  8.  
    for(let index of myArray) {
  9.  
    console.log(index)
  10.  
    }

输出结果是 a b c

使用for of无法输出索引值,但也不会输出数组的原型对象。

可中断

针对上面1.2.2中提及的问题,for of可以使用break进行解决

  1.  
    var arr = [3, 5, 7];
  2.  
     
  3.  
    for (let value of arr) {
  4.  
    console.log(value);
  5.  
    if (value == 5) {
  6.  
    break;
  7.  
    }
  8.  
    }

可迭代字符串

  1.  
    let str = 'hello';
  2.  
     
  3.  
    for (let value of str) {
  4.  
    console.log(value);
  5.  
    }

输出结果是 ‘h’ ‘e’ ‘l’ ‘l’ ‘o’

可迭代arguments类数组对象

  1.  
    (function() {
  2.  
    for (let argument of arguments) {
  3.  
    console.log(argument);
  4.  
    }
  5.  
    })(1, 2, 3);

输出结果是 1 2 3

可迭代map和set

  1.  
    let mapData = new Map([['a', 1], ['b', 2], ['c', 3]]);
  2.  
     
  3.  
    for (let [key, value] of mapData) {
  4.  
    console.log(value);
  5.  
    }
  6.  
     
  7.  
     
  8.  
    let setData = new Set([['a', 1], ['b', 2], ['c', 3]]);
  9.  
     
  10.  
    for (let [key, value] of setData) {
  11.  
    console.log(value);
  12.  
    }

for in 适用于纯对象的遍历,并且只能输出可枚举属性

forEach适用于需要知道索引值的数组遍历,但是不能中断

for of适用于无需知道索引值的数组遍历,因为可以中断。另外对于其他字符串,类数组,类型数组的迭代,for of也更适用

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgabcif
系列文章
更多 icon
同类精品
更多 icon
继续加载