javascript中罗列 迭代对象的要领

for…in

for…in 轮回只遍历可罗列属性。像 Array和 Object运用内置组织函数所建立的对象都邑继续自Object.prototype和String.prototype的不可罗列属性,比方 String 的 indexOf()要领或 Object的toString()要领。轮回将遍历对象本身的一切可罗列属性,以及对象从其组织函数原型中继续的属性(更靠近原型链中对象的属性掩盖原型属性)。
删除,增加或许修正属性
for…in 轮回以恣意序迭代一个对象的属性(请参阅delete运算符,相识为何不能依赖于迭代的外表有序性,至少在跨浏览器设置中)。假如一个属性在一次迭代中被修正,在稍后被接见,其在轮回中的值是其在稍后时候的值。一个在被接见之前已被删除的属性将不会在以后被接见。在迭代举行时被增加到对象的属性,能够在以后的迭代被接见,也能够被疏忽。

一般,在迭代历程当中最好不要在对象上举行增加、修正或许删除属性的操纵,除非是对当前正在被接见的属性。这里并不保证是不是一个被增加的属性在迭代历程当中会被接见到,不保证一个修正后的属性(除非是正在被接见的)会在修正前或许修正后被接见,不保证一个被删除的属性将会在它被删除之前被接见。

数组迭代和 for…in节

提醒:for…in不应该用于迭代一个 Array,个中索引递次很主要。

数组索引只是具有整数称号的罗列属性,而且与通用对象属性雷同。不能保证for … in将以任何特定的递次返回索引。for … in轮回语句将返回一切可罗列属性,包括非整数范例的称号和继续的那些。

因为迭代的递次是依赖于实行环境的,所以数组遍历不一定按序次接见元素。因而当迭代接见递次很主要的数组时,最好用整数索引去举行for轮回(或许运用 Array.prototype.forEach() 或 for…of 轮回)。

仅迭代本身的属性节

假如你只需斟酌对象本身的属性,而不是它的原型,那末运用 getOwnPropertyNames() 或实行 hasOwnProperty() 来肯定某属性是不是是对象本身的属性(也能运用propertyIsEnumerable)。或许,假如你晓得不会有任何外部代码滋扰,您能够运用搜检要领扩大内置原型。

示例

下面的函数接收一个对象作为参数。被调用时迭代传入对象的一切可罗列属性然后返回一个一切属性名和其对应值的字符串。

var obj = {a:1, b:2, c:3};

for (var prop in obj) {
console.log(“obj.” + prop + ” = ” + obj[prop]);
}

// Output:
// “obj.a = 1”
// “obj.b = 2”
// “obj.c = 3”
下面的函数说清楚明了hasOwnProperty()的用法:继续的属性不显现。

var triangle = {a: 1, b: 2, c: 3};

function ColoredTriangle() {
this.color = ‘red’;
}

ColoredTriangle.prototype = triangle;

var obj = new ColoredTriangle();

for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {

console.log(`obj.${prop} = ${obj[prop]}`);

}
}

// Output:
// “obj.color = red”

Object.keys()

用于猎取对象本身一切的可罗列的属性值,但不包括原型中的属性,然后返回一个由属性名构成的数组。注重它同for..in一样不能保证属性按对象本来的递次输出。

复制代码
// 遍历数组
var colors = [‘red’, ‘green’, ‘blue’];
colors.length = 10;
colors.push(‘yellow’);
Array.prototype.demo = function () {};

Object.keys(colors); // [“0”, “1”, “2”, “10”]

// 遍历对象
function Person(name, age) {
this.name = name;
this.age = age;
}

Person.prototype.demo = function() {};

var jenemy = new Person(‘jenemy’, 25);

Object.keys(jenemy); // [“name”, “age”]
复制代码
  注重在 ES5 环境,假如传入的参数不是一个对象,而是一个字符串,那末它会报 TypeError。在 ES6 环境,假如传入的是一个非对象参数,内部会对参数作一次强迫对象转换,假如转换不成功会抛出 TypeError。

复制代码
// 在 ES5 环境
Object.keys(‘foo’); // TypeError: “foo” is not an object

// 在 ES6 环境
Object.keys(‘foo’); // [“0”, “1”, “2”]

// 传入 null 对象
Object.keys(null); // Uncaught TypeError: Cannot convert undefined or null to object

// 传入 undefined
Object.keys(undefined); // Uncaught TypeError: Cannot convert undefined or null to object
复制代码
  因为Object.keys()为ES5上的要领,因而关于ES5以下的环境须要举行polyfill

复制代码
// From https://developer.mozilla.org…
if (!Object.keys) {
Object.keys = (function() {

'use strict';
var hasOwn = Object.prototype.hasOwnProperty,
    hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
    dontEnums = [
      'toString',
      'toLocaleString',
      'valueOf',
      'hasOwnProperty',
      'isPrototypeOf',
      'propertyIsEnumerable',
      'constructor'
    ],
    dontEnumsLength = dontEnums.length;

  return function(obj) {
    if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
      throw new TypeError('Object.keys called on non-object');
    }

    var result = [], prop, i;

    for (prop in obj) {
      if (hasOwn.call(obj, prop)) {
        result.push(prop);
      }
    }

    if (hasDontEnumBug) {
      for (i = 0; i < dontEnumsLength; i++) {
        if (hasOwn.call(obj, dontEnums[i])) {
          result.push(dontEnums[i]);
        }
      }
    }
    return result;
  }

}) ();
}

Object.getOwnPropertyNames()

Object.getOwnPropertyNames()要领返回一个由指定对象的一切本身属性的属性名(包括不可罗列属性但不包括Symbol值作为称号的属性)构成的数组。

Object.getOwnPropertyNames() 返回一个数组,该数组对元素是 obj本身具有的罗列或不可罗列属性称号字符串。 数组中罗列属性的递次与经由过程 for…in 轮回(或 Object.keys)迭代该对象属性时一致。数组中不可罗列属性的递次未定义。
var arr = [“a”, “b”, “c”];
console.log(Object.getOwnPropertyNames(arr).sort()); // [“0”, “1”, “2”, “length”]

// 类数组对象
var obj = { 0: “a”, 1: “b”, 2: “c”};
console.log(Object.getOwnPropertyNames(obj).sort()); // [“0”, “1”, “2”]

// 运用Array.forEach输出属性名和属性值
Object.getOwnPropertyNames(obj).forEach(function(val, idx, array) {
console.log(val + ” -> ” + obj[val]);
});
// 输出
// 0 -> a
// 1 -> b
// 2 -> c

//不可罗列属性
var my_obj = Object.create({}, {
getFoo: {

value: function() { return this.foo; },
enumerable: false

}
});
my_obj.foo = 1;

console.log(Object.getOwnPropertyNames(my_obj).sort()); // [“foo”, “getFoo”]
假如你只需猎取到可罗列属性,检察Object.keys或用for…in轮回(还会猎取到原型链上的可罗列属性,不过能够运用hasOwnProperty()要领过滤掉)。

下面的例子演示了该要领不会猎取到原型链上的属性:

function ParentClass() {}
ParentClass.prototype.inheritedMethod = function() {};

function ChildClass() {
this.prop = 5;
this.method = function() {};
}

ChildClass.prototype = new ParentClass;
ChildClass.prototype.prototypeMethod = function() {};

console.log(
Object.getOwnPropertyNames(

new ChildClass()  // ["prop", "method"]

)
);
只猎取不可罗列的属性节
下面的例子运用了 Array.prototype.filter() 要领,从一切的属性名数组(运用Object.getOwnPropertyNames()要领取得)中去除可罗列的属性(运用Object.keys()要领取得),盈余的属性就是不可罗列的属性了:

var target = myObject;
var enum_and_nonenum = Object.getOwnPropertyNames(target);
var enum_only = Object.keys(target);
var nonenum_only = enum_and_nonenum.filter(function(key) {

var indexInEnum = enum_only.indexOf(key);
if (indexInEnum == -1) {
    // 没有发如今enum_only健集合意味着这个健是不可罗列的,
    // 因而返回true 以便让它保持在过滤效果中
    return true;
} else {
    return false;
}

});

console.log(nonenum_only);
注:Array.filter(filt_func)要领建立一个新数组, 其包括经由过程所供应函数完成的测试的一切元素。
提醒节
在 ES5 中,假如参数不是一个原始对象范例,将抛出一个 TypeError 非常。在 ES2015 中,非对象参数被强迫转换为对象 。

Object.getOwnPropertyNames(‘foo’);
// TypeError: “foo” is not an object (ES5 code)

Object.getOwnPropertyNames(‘foo’);
// [‘length’, ‘0’, ‘1’, ‘2’] (ES2015 code)

    原文作者:yang
    原文地址: https://segmentfault.com/a/1190000018858732
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞