代码test1:

var obj = {}
Object.defineProperty(obj, 'method1', {value: function () {alert("Non enumerable property");},enumerable: false
})console.log(Object.keys(obj)) // []
console.log(Reflect.ownKeys(obj)) // ["method1"]

代码test2:

const obj = {id1: 42,id2: 13
};
console.log(Object.keys(obj)) // ['id1', 'id2']
console.log(Reflect.ownKeys(obj)) // ['id1', 'id2']

总结:
Object.keys()主要用于遍历对象自有的可枚举属性,不包括继承自原型的属性和不可枚举的属性。
Reflect.ownKeys()返回所有自有属性key,不管是否可枚举,但不包括继承自原型的属性

官方对Refelct.ownKeys()的描述如下:

The Reflect.ownKeys method returns an array of the target object's own property keys. Its return value is equivalent to Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)).


JS中遍历对象属性的三种方法:

for in

主要用于遍历对象的可枚举属性,包括自有属性、继承自原型的属性

Object.keys

返回一个数组,元素均为对象自有的可枚举属性

Object.getOwnPropertyNames

用于返回对象的自有属性,包括可枚举和不可枚举的

注意:


什么是枚举?枚举是指对象中的属性是否可以遍历出来,再简单点说就是属性是否可以被列举出来。

一、怎么判断属性是否可枚举

在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查找遍历到。

JS中的基本包装类型的原型属性是不可枚举的,基本包装类型看下图:

下面是一个例子:

var num = new Number();
for(var pro in num) {console.log("num." + pro + " = " + num[pro]);
}// 此处没有输出

它的输出结果是空的,因为Number的原型属性是不可枚举的,所以不能被 for ... in 访问到。

二、枚举属性的作用

枚举属性主要会影响几个方法

ES5中:
    for...in                         //只遍历对象自身的和继承的可枚举的属性
    Object.keys()             //返回对象自身的所有可枚举的属性的键名
    JSON.stringify           //JSON.stringify() 方法用于将 JavaScript 值转换为 JSON 字符串。
 ES6中:
    Object.assign()          //会忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。

可以看出来这些都是可以遍历对象的方法,而这四个操作中只有for...in中会返回继承的属性

先看一个例子,创建一个"xsy"对象:

function Person(){this.name = "XSY"
};
Person.prototype = {constructor: Person,job:"student",
};var xsy = new Person();
Object.defineProperty(xsy, "sex",{value:"female",enumerable:false
});

这里用defineProperty方法定义了一个叫"sex"的不可枚举属性

然后可以开始验证了:

a.  for...in

for(var pro in xsy){console.log("xsy." + pro+ " = " + xsy[pro]);
}

输出的结果如下,可以发现 对象中声明的属性,原型链上绑定的属性成功输出了,而不可枚举属性“sex”没有输出。

b.  Object.keys()

console.log(Object.keys(xsy));

从输出结果可以发现,这里只输出了对象声明的可枚举属性,但是没有输出原型链中的可枚举属性

c. JSON.stringify

console.log(JSON.stringify(xsy));

这里的输出也和上面一样,结果中只有对象中的可枚举属性没有原型链中的。

从上面这些操作中大概可以明白了,可枚举性决定了这个属性能否被for…in查找遍历到。所以可枚举与否都是开发者自己定义的,可以通过Object.defineProperty()方法。

三、设置可枚举属性

其实在上面的例子中已经使用到了设置enumerable的方法:Object.defineProperty()

var person = {name:'xiao',age: '18',sex: 'boy'
}Object.defineProperty(person,'age',{enumerable:true //可以被枚举
});
Object.defineProperty(person,'sex',{enumerable:false //不可以被枚举
})for(var k in person){console.log(person[k])
}//xiao
//18

从上面可以看出:

  1. Object.defineProperty(obj, prop, descriptor)方法有三个参数
    第一个:目标对象
    第二个:目标属性,字符串
    第三个:对目标属性的行为,放在对象里
  2. enumerable为true时表示可枚举,enumerable为false表示不可枚举;
  3. 开发者自己定义的对象person中的所有属性默认都是可枚举的;

四、如何判断是否可枚举 -- propertyIsEnumerable

每个对象都有propertyIsEnumerable()方法,这个方法可以判断出指定的属性是否可枚举。

用法: obj.propertyIsEnumerable("属性名");

  1. 这个属性必须属于实例的,并且不属于原型。
  2. 这个属性必须是可枚举的。
  3. 如果对象没有指定的属性,该方法返回false
function Person(){this.name = "我是实例属性"this.age = 19;
}
var p = new Person();
console.log(p.propertyIsEnumerable("name")); //truePerson.prototype.prop = "我是原型属性" //添加一个原型属性
console.log(p.propertyIsEnumerable("prop")); //false prop是继承自原型上的属性,所以返回的是falsefor(var k in p){console.log(k+","+p[k]); //name,我是实例属性  age,19  prop,我是原型属性
}

案例:
1)用户自定义对象和引擎内置对象的区别

Math.propertyIsEnumerable('random');   // 返回 false
Object.propertyIsEnumerable('constructor');    // 返回 false
var num = new Number();
for(var pro in num) {console.log("num." + pro + " = " + num[pro]);
}
//输出空

这说明了开发者自定义的属性在一般情况下时可以枚举的,但是内置的对象Math和基本包装类型里的属性是不可枚举的。

其实,propertyIsEnumerable方法只对对象自身的属性(对象自身添加的、构造函数实例化的)有效,对原型上的、继承来的属性都无效。

五、总结

实际上,引入enumerable的最初目的,就是让某些属性可以规避掉for...in操作。比如,对象原型的toString方法,以及数组的length属性,就通过这种手段,不会被for...in遍历到。

具体如下:

Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable
// false
Object.getOwnPropertyDescriptor([], 'length').enumerable
// false

另外, ES6 规定,所有 Class 的原型的方法都是不可枚举的。

Object.getOwnPropertyDescriptor(class {foo() {}}.prototype, 'foo').enumerable
// false

总的来说,操作中引入继承的属性会让问题复杂化,大多数时候,我们只关心对象自身的属性。所以,尽量不要用for...in循环,而用Object.keys()代替。

Reflect.ownKeys()与Object.keys()区别 以及 JS中的可枚举属性与不可枚举属性相关推荐

  1. append和appendTo的区别以及js中的appendChild用法

    append和appendTo的区别以及js中的appendChild用法 很多像我一样接触JS没多久的小白对append和appendTo的区别以及js中的appendChild用法都会有所模糊,下 ...

  2. 可枚举属性和不可枚举属性(for...in循环和Objec.keys()和Object.getOwnPropertyNames())

    可枚举属性和不可枚举属性(for...in循环和Objec.keys()和Object.getOwnPropertyNames()) for...in循环是 遍历对象的每一个可枚举属性,包括原型链上面 ...

  3. JS中的可枚举属性与不可枚举属性的学习以及扩展

    最近在学习对象遍历的方法时总是能看到的两个词,一个是"原型",一个是"枚举属性".一开始感觉自己大概明白"枚举属性"的意思,但是叫我解释却又 ...

  4. js对象转数组可枚举属性和不可枚举属性

    前言 项目里面很多地方我们需要把数据处理一下才能应用,包括我们拿到的是一个对象,但是我们需要遍历,这个时候就需要把对象转成数组来实现我们的目的了,js对象转数组有几种方法,归纳整理一下- js对象转数 ...

  5. js的可枚举属性与不可枚举属性

    可枚举属性和不可枚举属性什么意思? 在javascript中,对象的属性可以分为可枚举属性和不可枚举属性,它们的属性由enumerable值决定,可枚举属性决定了这个属性能否被for in 遍历到 判 ...

  6. js 中的可枚举属性

    前言 首先,可枚举属性是指那些内部 "可枚举" 标志设置为 true 的属性,而这个"可枚举"标志,即enumerable. 对于通过直接的赋值和属性初始化的属 ...

  7. JS对象的可枚举属性和不可枚举属性

    昨天在写文章(转载)的时候发现了有些对象的方法是分可枚举性和不可枚举性的. 简单的查了一下资料,今天来捋一捋啥是对象的可枚举啥是不可枚举. JS中对象转数组方法总结 可枚举性: 对象的每一个属性都有一 ...

  8. JS中的可枚举属性与不可枚举属性

    一.怎么判断属性是否可枚举 js中基本包装类型的原型属性是不可枚举的,如Object, Array, Number等,如果你写出这样的代码遍历其中的属性: var num = new Number() ...

  9. JS中常用的键盘事件与keycode属性

    JS中的键盘事件与keycode属性 键盘事件 键盘事件与鼠标事件类似,同样常出现在开发过程中. 简单介绍三个常见的键盘事件 keydown (识别所有键) keyup (识别所有键) keypres ...

最新文章

  1. app.config中增加appSettings节点,conn.open时报初始化错误
  2. Centos7常用操作
  3. 【Linux 报错】com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure The las
  4. Linux压缩解压缩命令
  5. adapter为null_软件设计精要之——适配器(Adapter)模式
  6. 采用开源技术的好处_采用开源的6个技巧
  7. 中国网吧 20 年往事,端游式微、手游主宰
  8. WAF和IPS的区别
  9. 看我72变:解决Entity Framework中枚举类型与tinyint的映射问题
  10. Framework层SMS发送
  11. python迭代器、生成器和yield语句
  12. android:gravity与android:layout_gravity的区别,以及代码设置对应属性
  13. c语言常量ascii码表,C语言常用转义符和ASCII码表
  14. tplink查看上网记录_Tplink路由器PPPOE拨号不能上网日志查看原因
  15. 有赞搜索系统的技术内幕
  16. 开放计算何处觅?JDM安天下
  17. chrome浏览器改为黑色背景
  18. 春夜宴诸从弟桃李园序 李白
  19. STM32F4学习笔记1
  20. java 移动端session失效,Session is invalid

热门文章

  1. 当我们打开网页时,浏览器究竟做了什么
  2. 苹果手机使用物联网卡开不了热点是怎么回事?
  3. 官网下载Android Studio下载不了
  4. PHP MySQL 中文帮助 在线手册
  5. zencart免费模板下载
  6. 超级兔子虚拟磁盘加速器1.62
  7. 文件上传漏洞防范措施
  8. Python 炫技操作(九):调用函数的九种方法
  9. Docker - ENTRYPOINT
  10. Winows 8 激活方法