遍历对象:一文搞懂for in、for of、Object.keys()、Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()的区别

获取对象不同类型属性的相关方法

一、对象属性理解

比如:数组中的length属性,描述符对象enumerable值为false,隐式属性。

看下正常的数组和对象的属性:

        var arr = ["a", true, 3]
        var obj = {
            name: "zhu",
            age: 24
        }
        console.log(arr)
        console.log(obj)

二、关于遍历

1、for...in循环(自身显式的属性,意外的获取了原型链上的属性)

只遍历显式属性和原型链上的显式属性, 当然也可以遍历数组。

        var sym = Symbol("foo");
        var arr = ["a", true, 3];
        var obj = {
            name: "zhu",
            age: 24,
            [sym]: "symbol-foo",
            [Symbol("bar")]: "symbol-bar"
        }
        //age为隐式属性
        Object.defineProperty(obj, "age", {
            enumerable: false
        })
        //原型上的属性
        obj.__proto__ = {
            fa: "father"
        }
        var objStack = [];
        var arrStack = [];
        for(var prop in obj){
            objStack.push(prop)
        }
        for(var i in arr){
            arrStack.push(i)
        }
        console.log(objStack)
        console.log(arrStack)
["name", "fa"]
["0", "1", "2"]

 所以我们在使用for in 遍历的时候,防止遍历到原型链上的属性,我们会用hasOwnProperty方法来判断是不是对象本身的属性

console.log(obj.hasOwnProperty("fa"))

 而 in 方法可以判断属性是不是对象原型及原型链上的属性

console.log("fa" in obj )

2、for...of循环 

只遍历iterable类型的值,且处理的是iterable的值,而非属性或键;对象不是iterable类型

        var arrStack = [];
        var arr = ["a", true, 3, sym, Symbol("bar")];
        for(var i of arr){  
            arrStack.push(i)
        }
        console.log(arrStack) //["a", true, 3, Symbol(foo), Symbol(bar)]

3、Object.keys()方法(自身显式的属性)

返回指定对象自身可枚举属性名称组成的数组。——兼容性IE9,ES5方法,还不会处理Symbol属性

        var sym = Symbol("foo");
        var arr = ["a", true, 3];
        var obj = {
            name: "zhu",
            age: 24,
            [sym]: "symbol-foo",
            [Symbol("bar")]: "symbol-bar"
        }
        //age为隐式属性
        Object.defineProperty(obj, "age", {
            enumerable: false
        })
        //原型上的属性
        obj.__proto__ = {
            fa: "father"
        }

        console.log(Object.keys(obj)) //["name"]
        console.log(Object.keys(arr)) //["0", "1", "2"]

4、Object.getOwnPropertyNames()方法、兼容性ES5  IE9——自身可枚举的和不可枚举的属性——ES5方法,不处理Symbol属性

返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。即获取对象自身的所有属性,不包含Symbol属性。

即自身显式的和隐式的属性

        var sym = Symbol("foo");
        var arr = ["a", true, 3];
        var obj = {
            name: "zhu",
            age: 24,
            [sym]: "symbol-foo",
            [Symbol("bar")]: "symbol-bar"
        }
        //age为隐式属性
        Object.defineProperty(obj, "age", {
            enumerable: false
        })
        //原型上的属性
        obj.__proto__ = {
            fa: "father"
        }
        console.log(Object.getOwnPropertyNames(obj)) //["name", "age"]
        console.log(Object.getOwnPropertyNames(arr)) //["0", "1", "2", "length"]

该数组对元素是 obj自身拥有的枚举或不可枚举属性名称字符串。 数组中枚举属性的顺序与通过 for...in 循环(或 Object.keys)迭代该对象属性时一致。数组中不可枚举属性的顺序未定义

数组:数组的顺序 (不可枚举的属性位定义顺序——跟对象属性顺序一样)

var arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort());  ["0", "1", "2", "length"]

类数组:

        function foo(){
            console.log(arguments);
            console.log(Object.getOwnPropertyNames(arguments))
        }
        foo("zhu",true,3,5);

结果:

对象:

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()方法过滤掉) 

 5、Object.getOwnPropertySymbols()方法——自身Symbol属性,ES6  Edge12方法返回一个给定对象自身的所有 Symbol 属性的数组。——ES6方法,专门处理Symbol属性

获取对象自身的Symbol属性

        var sym = Symbol("foo");
        var arr = ["a", true, 3];
        var obj = {
            name: "zhu",
            age: 24,
            [sym]: "symbol-foo",
            [Symbol("bar")]: "symbol-bar"
        }
        //age为隐式属性
        Object.defineProperty(obj, "age", {
            enumerable: false
        })
        //原型上的属性
        obj.__proto__ = {
            fa: "father"
        }
        console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(foo), Symbol(bar)]
        console.log(Object.getOwnPropertySymbols(arr)) //[]

Object.getOwnPropertyNames()类似,您可以将给定对象的所有符号属性作为 Symbol 数组获取。 请注意,Object.getOwnPropertyNames()本身不包含对象的 Symbol 属性,只包含字符串属性。因为所有的对象在初始化的时候不会包含任何的 Symbol,除非你在对象上赋值了 Symbol 否则Object.getOwnPropertySymbols()只会返回一个空的数组。

var obj = {};
var a = Symbol("a");
var b = Symbol.for("b");

obj[a] = "localSymbol";
obj[b] = "globalSymbol";

var objectSymbols = Object.getOwnPropertySymbols(obj);

console.log(objectSymbols.length); // 2
console.log(objectSymbols)         // [Symbol(a), Symbol(b)]
console.log(objectSymbols[0])      // Symbol(a)

6、Object.values

Object.values()方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。

Object.values()返回一个数组,其元素是在对象上找到的可枚举属性值。属性的顺序与通过手动循环对象的属性值所给出的顺序相同。

var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj)); // ['a', 'b', 'c']

兼容性不是很好,Edge14 Chrome54,可以根据keys方法实现一个polyfill

if (!Object.values) Object.values = function(obj) {
    if (obj !== Object(obj))
        throw new TypeError('Object.values called on a non-object');
    var val=[],key;
    for (key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj,key)) {
            val.push(obj[key]);
        }
    }
    return val;
}

 

7、Object.entries

Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。

返回值:给定对象自身可枚举属性的键值对数组。

Object.entries()返回一个数组,其元素是与直接在object上找到的可枚举属性键值对相对应的数组。属性的顺序与通过手动循环对象的属性值所给出的顺序相同。

const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]

object对象转Map对象

var obj = { foo: "bar", baz: 42 };
var map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }

兼容性:Edge14 Chrome54,兼容性不是很好,可以通过keys方法来实现一个polyfill:

if (!Object.entries)
  Object.entries = function( obj ){
    var ownProps = Object.keys( obj ),
        i = ownProps.length,
        resArray = new Array(i); // preallocate the Array
    while (i--)
      resArray[i] = [ownProps[i], obj[ownProps[i]]];

    return resArray;
  }

若想支持IE8,替换上面Object.keys

三、总结

(1)for in获取对象的显式属性,因为是早期版本,也会获取原型链上的显式属性

(2)Object.keys()  ES5的方法,对上面方法进行优化,只获取对象本身的显式属性,不考虑隐式属性和Symbol属性,因为Symbol属性是ES6新增的。

(3)Object.getOwnPropertyNames()方法,ES5方法,获取对象自身显式的和隐式的属性,不考虑Symbol属性,因为Symbol属性是ES6新增的。

(4)Object.getOwnPropertySymbols()方法,ES6方法,获取对象自身的Symbol属性。专门获取对象自身的Symbol属性。

(5)Object.values() 和 Object.entries()方法,兼容性Edge14 Chrome54兼容性不好,可以通过Object.keys()方法来做兼容

 

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值