zoukankan      html  css  js  c++  java
  • JavaScript中对象和数组的遍历方法

    对象的遍历

    对象属性的遍历,方法有以下几种

    • for...in
    • Object.keys()
    • Object.getOwnPropertyNames()

    1. for...in

    for...in语句以任意顺序遍历一个对象的除Symbol以外的可枚举属性。

    可枚举属性与不可枚举属性:
    在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。
    可枚举性决定了这个属性能否被for…in查找遍历到。
    js中基本包装类型的原型属性是不可枚举的,如Object, Array, Number等,
    如果你写出这样的代码遍历其中的属性:
    
    var num = new Number();
    for(var pro in num) {
        console.log("num." + pro + " = " + num[pro]);
    }
    //输出空
    这是因为Number中内置的属性是不可枚举的,所以不能被for…in访问到。
    
    语法
    var obj = {
        name: 'jack',
        age: 33
    }
    for (var n in obj) {
        console.log(n)
    }
    输出:name, age
    

    注意:

    通常为了只枚举对象的私有属性,会用一个判断函数hasOwnProperty()来过滤掉原型中的属性

    Object.prototype.hasOwnProperty方法接受一个字符串作为参数,返回一个布尔值,表示该实例对象自身是否具有该属性。

    例1:
    Object.prototype.clone = function() {}
    var obj = {
        name: 'jack',
        age: 33
    }
    for (var n in obj) {
        console.log(n)
    }
    //多出了在原型上定义的方法
    输出:name, age, clone
    
    例2:
    Object.prototype.clone = function () {};
    var obj = {
      name: "jack",
      age: 33,
    };
    for (var n in obj) {
      if (obj.hasOwnProperty(key)) {
        console.log(n);
      }
    }
    
    输出:name, age
    #推荐总是使用 hasOwnProperty 方法,这将会避免原型对象扩展带来的干扰:
    

    2. Object.keys() , Object.getOwnPropertyNames()

    Object.keys方法的参数是一个对象,返回一个数组。该数组的成员都是该对象自身的(而不是继承的)所有属性名。

    一般情况下,几乎总是使用Object.keys方法,遍历对象的属性。

    语法
    var obj = {
      p1: 123,
      p2: 456
    };
    
    Object.keys(obj) // ["p1", "p2"]
    
    var obj = {
      p1: 123,
      p2: 456
    };
    
    Object.getOwnPropertyNames(obj) // ["p1", "p2"]
    

    对于一般的对象来说,Object.keys()Object.getOwnPropertyNames()返回的结果是一样的。只有涉及不可枚举属性时,才会有不一样的结果。
    Object.keys方法只返回可枚举的属性(详见《对象属性的描述对象》一章),Object.getOwnPropertyNames方法还返回不可枚举的属性名。

    var a = ['Hello', 'World'];
    
    Object.keys(a) // ["0", "1"]
    Object.getOwnPropertyNames(a) // ["0", "1", "length"]
    //上面代码中,数组的length属性是不可枚举的属性,所以只出现在Object.getOwnPropertyNames方法的返回结果中。
    

    小结

    • for..in 遍历的是对象的可枚举属性,包括原型
    • Object.keys 遍历的是对象可枚举属性,不包括原型
    • Object.getOwnPropertNames 遍历的是对象的所有属性,不包括原型

    数组项的全部遍历

    全部遍历所列举的方法,是指主要用来枚举数组各项的方法。

    1. for循环

    for循环遍历是最原始,也是性能最高的一种遍历方法。

    var arr = [1,4,7,9]
    for (var i = 0, len = arr.length; i < len; i++) {
        console.log(arr[i]) // 输出 1 4 7 9
    }
    

    2. forEach函数

    forEach()函数是构造函数Array的原型上的函数,即Array.prototype.forEach,因此所有数组都可以用这个方法。
    函数没有返回值,因此主要用来对数组的过程处理。

    forEach方法的回调函数有三个参数,elem为当前成员的值,index为当前成员的位置,arr为原数组([1, 2, 3])。
    var arr = ['a', 'b', 'c']
    arr.forEach((elem, index, arr) => { // 处理函数作为参数
        console.log(index + ' is ' + elem)
    })
    输出
    0 is a
    1 is b
    2 is c
    

    3. map函数

    map()函数也是构造函数Array的原型上的函数,即Array.prototype.mapmap方法将数组的所有成员依次传入参数函数,然后把每一次的执行结果组成一个新数组返回。

    map方法向它传入三个参数:当前成员、当前位置和数组本身。
    [1, 2, 3].map((elem, index, arr)=> {
      return elem * index;
    });
    // [0, 2, 6]
    

    4. for...of

    for...of是ES6新增的语法,它不仅可以用来遍历数组,还可以遍历字符串,以及ES6中的Map,Set。

    var array = ['a', 'b', 'c']
    for (let item of array) {
        console.log(item) // 输出 a b c
    }
    

    数组项的其他遍历

    1. filter()函数

    filter方法用于过滤数组成员,满足条件的成员组成一个新数组返回。

    它的参数是一个函数,所有数组成员依次执行该函数,返回结果为true的成员组成一个新数组返回。该方法不会改变原数组。

    filter方法的参数函数可以接受三个参数:当前成员,当前位置和整个数组。
    [1, 2, 3, 4, 5].filter( elem=> {
      return (elem > 3);
    })
    //输出 [4, 5]
    

    2. some(),every()

    这两个方法类似“断言”(assert),返回一个布尔值,表示判断数组成员是否符合某种条件。

    它们接受一个函数作为参数,所有数组成员依次执行该函数。该函数接受三个参数:当前成员、当前位置和整个数组,然后返回一个布尔值。

    some方法是只要一个成员的返回值是true,则整个some方法的返回值就是true,否则返回false

    代码中,如果数组`arr`有一个成员大于等于3,`some`方法就返回`true`
    var arr = [1, 2, 3, 4, 5];
    arr.some( (elem, index, arr)=> {
      return elem >= 3;
    });
    // true
    

    every方法是所有成员的返回值都是true,整个every方法才返回true,否则返回false

    代码中,数组`arr`并非所有成员大于等于`3`,所以返回`false`。
    var arr = [1, 2, 3, 4, 5];
    arr.every(function (elem, index, arr) {
      return elem >= 3;
    });
    // false
    

    注意,对于空数组,some方法返回falseevery方法返回true,回调函数都不会执行。

    3. reduce(),reduceRight()

    reduce方法和reduceRight方法依次处理数组的每个成员,最终累计为一个值。它们的差别是,reduce是从左到右处理(从第一个成员到最后一个成员),reduceRight则是从右到左(从最后一个成员到第一个成员),其他完全一样。

    [1, 2, 3, 4, 5].reduce(function (a, b) {
      console.log(a, b);
      return a + b;
    })
    // 1 2
    // 3 3
    // 6 4
    // 10 5
    //最后结果:15
    

    上面代码中,reduce方法求出数组所有成员的和。整个方法的返回值就是最后一轮的返回值15

    reduce方法和reduceRight方法的第一个参数都是一个函数。该函数接受以下四个参数。

    1. 累积变量,默认为数组的第一个成员
    2. 当前变量,默认为数组的第二个成员
    3. 当前位置(从0开始)
    4. 原数组

    这四个参数之中,只有前两个是必须的,后两个则是可选的。

    如果要对累积变量指定初值,可以把它放在reduce方法和reduceRight方法的第二个参数。

    [1, 2, 3, 4, 5].reduce(function (a, b) {
      return a + b;
    }, 10);
    // 25
    

    上面代码指定参数a的初值为10,所以数组从10开始累加,最终结果为25。注意,这时b是从数组的第一个成员开始遍历。

    上面的第二个参数相当于设定了默认值,处理空数组时尤其有用。

    function add(prev, cur) {
      return prev + cur;
    }
    
    [].reduce(add)
    //错误:没有初始值的空数组
    // TypeError: Reduce of empty array with no initial value
    
    [].reduce(add, 1)
    // 1
    

    上面代码中,由于空数组取不到初始值,reduce方法会报错。这时,加上第二个参数,就能保证总是会返回一个值。

    由于这两个方法会遍历数组,所以实际上还可以用来做一些遍历相关的操作。比如,找出字符长度最长的数组成员。

    function findLongest(entries) {
      return entries.reduce(function (longest, entry) {
        return entry.length > longest.length ? entry : longest;
      }, '');
    }
    
    findLongest(['aaa', 'bb', 'c']) // "aaa"
    

    上面代码中,reduce的参数函数会将字符长度较长的那个数组成员,作为累积值。这导致遍历所有成员之后,累积值就是字符长度最长的那个成员。

    4. indexOf(),lastIndexOf()

    indexOf方法返回给定元素在数组中第一次出现的位置,如果没有出现则返回-1

    var a = ['a', 'b', 'c'];
    
    a.indexOf('b') // 1
    a.indexOf('y') // -1
    

    indexOf方法还可以接受第二个参数,表示搜索的开始位置。

    ['a', 'b', 'c'].indexOf('a', 1) // -1
    

    上面代码从1号位置开始搜索字符a,结果为-1,表示没有搜索到。

    lastIndexOf方法返回给定元素在数组中最后一次出现的位置,如果没有出现则返回-1

    var a = [2, 5, 9, 2];
    a.lastIndexOf(2) // 3
    a.lastIndexOf(7) // -1
    

    注意,这两个方法不能用来搜索NaN的位置,即它们无法确定数组成员是否包含NaN

    [NaN].indexOf(NaN) // -1
    [NaN].lastIndexOf(NaN) // -1
    

    这是因为这两个方法内部,使用严格相等运算符(===)进行比较,而NaN是唯一一个不等于自身的值。

  • 相关阅读:
    Sqlserver 实际开发中表变量的用法
    Python Day 20 面向对象 (面向对象的组合用法,面向对象的三大特性
    Python Day 19 面向对象(初识面向对象)
    Python Day 18 常用模块(模块和包)
    Python Day 17 常用模块(常用模块一 时间模块,random模块,os模块,sys模块,序列化模块)
    Python Day 15 函数(递归函数、二分查找算法)
    Python Day 14 函数(内置函数,匿名函数(lambda表达式))
    Python Day 13 函数(迭代器,生成器,列表推导式,生成器表达式)
    Python Day 11 + Python Day 12 函数(函数名的应用,闭包,装饰器)
    Python Day 10 函数(名称空间,作用域,作用域链,加载顺序等; 函数的嵌套 global,nonlocal)
  • 原文地址:https://www.cnblogs.com/cjh1996/p/12699512.html
Copyright © 2011-2022 走看看