Reflect.ownKeys()与Object.keys()区别 以及 JS中的可枚举属性与不可枚举属性
代码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
从上面可以看出:
- Object.defineProperty(obj, prop, descriptor)方法有三个参数
第一个:目标对象
第二个:目标属性,字符串
第三个:对目标属性的行为,放在对象里 - enumerable为true时表示可枚举,enumerable为false表示不可枚举;
- 开发者自己定义的对象person中的所有属性默认都是可枚举的;
四、如何判断是否可枚举 -- propertyIsEnumerable
每个对象都有propertyIsEnumerable()方法,这个方法可以判断出指定的属性是否可枚举。
用法: obj.propertyIsEnumerable("属性名");
- 这个属性必须属于实例的,并且不属于原型。
- 这个属性必须是可枚举的。
- 如果对象没有指定的属性,该方法返回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中的可枚举属性与不可枚举属性相关推荐
- append和appendTo的区别以及js中的appendChild用法
append和appendTo的区别以及js中的appendChild用法 很多像我一样接触JS没多久的小白对append和appendTo的区别以及js中的appendChild用法都会有所模糊,下 ...
- 可枚举属性和不可枚举属性(for...in循环和Objec.keys()和Object.getOwnPropertyNames())
可枚举属性和不可枚举属性(for...in循环和Objec.keys()和Object.getOwnPropertyNames()) for...in循环是 遍历对象的每一个可枚举属性,包括原型链上面 ...
- JS中的可枚举属性与不可枚举属性的学习以及扩展
最近在学习对象遍历的方法时总是能看到的两个词,一个是"原型",一个是"枚举属性".一开始感觉自己大概明白"枚举属性"的意思,但是叫我解释却又 ...
- js对象转数组可枚举属性和不可枚举属性
前言 项目里面很多地方我们需要把数据处理一下才能应用,包括我们拿到的是一个对象,但是我们需要遍历,这个时候就需要把对象转成数组来实现我们的目的了,js对象转数组有几种方法,归纳整理一下- js对象转数 ...
- js的可枚举属性与不可枚举属性
可枚举属性和不可枚举属性什么意思? 在javascript中,对象的属性可以分为可枚举属性和不可枚举属性,它们的属性由enumerable值决定,可枚举属性决定了这个属性能否被for in 遍历到 判 ...
- js 中的可枚举属性
前言 首先,可枚举属性是指那些内部 "可枚举" 标志设置为 true 的属性,而这个"可枚举"标志,即enumerable. 对于通过直接的赋值和属性初始化的属 ...
- JS对象的可枚举属性和不可枚举属性
昨天在写文章(转载)的时候发现了有些对象的方法是分可枚举性和不可枚举性的. 简单的查了一下资料,今天来捋一捋啥是对象的可枚举啥是不可枚举. JS中对象转数组方法总结 可枚举性: 对象的每一个属性都有一 ...
- JS中的可枚举属性与不可枚举属性
一.怎么判断属性是否可枚举 js中基本包装类型的原型属性是不可枚举的,如Object, Array, Number等,如果你写出这样的代码遍历其中的属性: var num = new Number() ...
- JS中常用的键盘事件与keycode属性
JS中的键盘事件与keycode属性 键盘事件 键盘事件与鼠标事件类似,同样常出现在开发过程中. 简单介绍三个常见的键盘事件 keydown (识别所有键) keyup (识别所有键) keypres ...
最新文章
- app.config中增加appSettings节点,conn.open时报初始化错误
- Centos7常用操作
- 【Linux 报错】com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure The las
- Linux压缩解压缩命令
- adapter为null_软件设计精要之——适配器(Adapter)模式
- 采用开源技术的好处_采用开源的6个技巧
- 中国网吧 20 年往事,端游式微、手游主宰
- WAF和IPS的区别
- 看我72变:解决Entity Framework中枚举类型与tinyint的映射问题
- Framework层SMS发送
- python迭代器、生成器和yield语句
- android:gravity与android:layout_gravity的区别,以及代码设置对应属性
- c语言常量ascii码表,C语言常用转义符和ASCII码表
- tplink查看上网记录_Tplink路由器PPPOE拨号不能上网日志查看原因
- 有赞搜索系统的技术内幕
- 开放计算何处觅?JDM安天下
- chrome浏览器改为黑色背景
- 春夜宴诸从弟桃李园序 李白
- STM32F4学习笔记1
- java 移动端session失效,Session is invalid