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

墨蓝 2022-12-17 03:26 177阅读 0赞

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

一、对象属性理解

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p5ejAwMDAwMDAw_size_16_color_FFFFFF_t_70

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

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

  1. var arr = ["a", true, 3]
  2. var obj = {
  3. name: "zhu",
  4. age: 24
  5. }
  6. console.log(arr)
  7. console.log(obj)

20201021164246307.png

二、关于遍历

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

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

  1. var sym = Symbol("foo");
  2. var arr = ["a", true, 3];
  3. var obj = {
  4. name: "zhu",
  5. age: 24,
  6. [sym]: "symbol-foo",
  7. [Symbol("bar")]: "symbol-bar"
  8. }
  9. //age为隐式属性
  10. Object.defineProperty(obj, "age", {
  11. enumerable: false
  12. })
  13. //原型上的属性
  14. obj.__proto__ = {
  15. fa: "father"
  16. }
  17. var objStack = [];
  18. var arrStack = [];
  19. for(var prop in obj){
  20. objStack.push(prop)
  21. }
  22. for(var i in arr){
  23. arrStack.push(i)
  24. }
  25. console.log(objStack)
  26. console.log(arrStack)
  27. ["name", "fa"]
  28. ["0", "1", "2"]

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

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

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

  1. console.log("fa" in obj )

2、for...of循环

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

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

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

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

  1. var sym = Symbol("foo");
  2. var arr = ["a", true, 3];
  3. var obj = {
  4. name: "zhu",
  5. age: 24,
  6. [sym]: "symbol-foo",
  7. [Symbol("bar")]: "symbol-bar"
  8. }
  9. //age为隐式属性
  10. Object.defineProperty(obj, "age", {
  11. enumerable: false
  12. })
  13. //原型上的属性
  14. obj.__proto__ = {
  15. fa: "father"
  16. }
  17. console.log(Object.keys(obj)) //["name"]
  18. console.log(Object.keys(arr)) //["0", "1", "2"]

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

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

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

  1. var sym = Symbol("foo");
  2. var arr = ["a", true, 3];
  3. var obj = {
  4. name: "zhu",
  5. age: 24,
  6. [sym]: "symbol-foo",
  7. [Symbol("bar")]: "symbol-bar"
  8. }
  9. //age为隐式属性
  10. Object.defineProperty(obj, "age", {
  11. enumerable: false
  12. })
  13. //原型上的属性
  14. obj.__proto__ = {
  15. fa: "father"
  16. }
  17. console.log(Object.getOwnPropertyNames(obj)) //["name", "age"]
  18. console.log(Object.getOwnPropertyNames(arr)) //["0", "1", "2", "length"]

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

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

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

类数组:

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

结果:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3p5ejAwMDAwMDAw_size_16_color_FFFFFF_t_70 1

对象:

  1. var my_obj = Object.create({}, {
  2. getFoo: {
  3. value: function() { return this.foo; },
  4. enumerable: false
  5. }
  6. });
  7. my_obj.foo = 1;
  8. console.log(Object.getOwnPropertyNames(my_obj).sort()); ["foo", "getFoo"]

如果你只要获取到可枚举属性,查看Object.keys或用for...in循环(还会获取到原型链上的可枚举属性,不过可以使用hasOwnProperty()方法过滤掉)

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

获取对象自身的Symbol属性

  1. var sym = Symbol("foo");
  2. var arr = ["a", true, 3];
  3. var obj = {
  4. name: "zhu",
  5. age: 24,
  6. [sym]: "symbol-foo",
  7. [Symbol("bar")]: "symbol-bar"
  8. }
  9. //age为隐式属性
  10. Object.defineProperty(obj, "age", {
  11. enumerable: false
  12. })
  13. //原型上的属性
  14. obj.__proto__ = {
  15. fa: "father"
  16. }
  17. console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(foo), Symbol(bar)]
  18. console.log(Object.getOwnPropertySymbols(arr)) //[]

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

  1. var obj = {};
  2. var a = Symbol("a");
  3. var b = Symbol.for("b");
  4. obj[a] = "localSymbol";
  5. obj[b] = "globalSymbol";
  6. var objectSymbols = Object.getOwnPropertySymbols(obj);
  7. console.log(objectSymbols.length); // 2
  8. console.log(objectSymbols) // [Symbol(a), Symbol(b)]
  9. console.log(objectSymbols[0]) // Symbol(a)

6、Object.values

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

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

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

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

  1. if (!Object.values) Object.values = function(obj) {
  2. if (obj !== Object(obj))
  3. throw new TypeError('Object.values called on a non-object');
  4. var val=[],key;
  5. for (key in obj) {
  6. if (Object.prototype.hasOwnProperty.call(obj,key)) {
  7. val.push(obj[key]);
  8. }
  9. }
  10. return val;
  11. }

7、Object.entries

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

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

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

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

object对象转Map对象

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

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

  1. if (!Object.entries)
  2. Object.entries = function( obj ){
  3. var ownProps = Object.keys( obj ),
  4. i = ownProps.length,
  5. resArray = new Array(i); // preallocate the Array
  6. while (i--)
  7. resArray[i] = [ownProps[i], obj[ownProps[i]]];
  8. return resArray;
  9. }

若想支持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()方法来做兼容

发表评论

表情:
评论列表 (有 0 条评论,177人围观)

还没有评论,来说两句吧...

相关阅读

    相关 static(

    一、聊一聊static与JVM Java 把内存分为栈内存和堆内存,其中栈内存用来存放一些基本类型的变量、数组和对象的引用,堆内存主要存放一些对象。在 JVM 加载一个类的

    相关 ThreadPoolExecutor

    前言 线程池是Java中使用较多的并发框架,合理使用线程池,可以:降低资源消耗,提高响应速度,提高线程的可管理性。 本篇文章将从线程池简单原理,线程池的创建,线程池执行

    相关 DDD

    最近看了很多和DDD相关的内容,这篇文章对DDD做一个总结,希望可以通过这篇文章不但知道什么是DDD,而且还可以知道如何实施DDD 一、什么是DDD DDD(领域驱动设