在JavaScript中,对象的属性有可枚举和不可枚举之分,它是由对象属性描述符enumerable
决定的。如果该属性是可枚举性的那么这个属性就能被for…in
查找遍历到。
对象的属性描述符 |
在JavaScript中可以通过Object.defineProperty()来为对象设置属性描述符。
从ES5开始,添加了对对象属性描述符的支持。现在JavaScript中支持6种属性描述符:
configurable
:设为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。enumerable
: 设置为true的时候该属性才会出现在对象的枚举属性中。value
: 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等),默认值undefined
。writable
: 设置为true的时候,value才能被赋值运算符改变。改变。get
: 属性的 getter 函数。当访问该属性时,才会调用此函数,执行时不传入任何参数,但是会传入 this 对象。该函数的返回值会被用作属性的值。默认值undefined
。set
:属性的 setter 函数。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。默认值undefined
。
Object.defineProperty() |
Object.defineProperty(obj, prop, descriptor)
使用Object.defineProperty()
定义属性
-
通过
Object.defineProperty()
定义的属性,enumerable,configurable,writable这几个值默认为false -
直接为对象动态添加属性,enumerable,configurable,writable这几个值默认为true
let cat ={name:'猫'}
Object.defineProperty(cat, "sound", {
enumerable: false,
configurable: false,
writable: false,
value: "喵喵"
});
//对象动态添加属性
cat.age=2
哪些是可枚举属性? |
enumerable:true
的属性即为可枚举属性- 基本包装类型的原型属性都是不可枚举的,如Object, Array, Number等
直观看到可枚举属性 |
谷歌浏览器控制台查看对象属性,深色的属性就是可枚举属性,浅色的属性就是不可枚举属性。
与枚举属性有关的几个方法 |
Object.getOwnPropertyNames()
获取对象自身所有的属性键名,包括可枚举和不可枚举的属性。Object.keys()
获取对象自身的可枚举属性键名,返回键名数组。obj.propertyIsEnumerable()
判断对象实例obj自身的属性是否为可枚举。for...in
遍历对象自身的和原型链上的可枚举的属性。可配合hasOwnProperty()
只获取自身可枚举属性Object.values()
获取对象自身的可枚举属性的值,返回值数组。Object.entries()
获取对象自身的可枚举属性的键值对,每个键值对以数组的形式存储,返回键值对数组集。
以上几个方法除了for...in
外其他的方法都无法遍历到原型链的属性。
Reflect.ownKeys()
获取对象自身所有的属性键名,包括Symbol类型属性Object.getOwnPropertySymbols()
获取对象自身Symbol类型属性
Symbol 作为属性名,遍历对象的时候,该属性不会出现在for...in、for...of
循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()
返回。
属性枚举与否有何用? |
设置为不可枚举后,for...in
就无法获取到对象上对应的属性。比如有些场景下你不希望这个属性被获取到。
🌰Object.defineProperty()
定义的属性默认不可枚举
🌰Object.getOwnPropertyNames()
获取对象自身所有的属性键名
let cat ={name:'猫'}
Object.defineProperty(cat, "sound", {
// enumerable: false,
// configurable: false,
// writable: false,
value: "喵喵"
});
console.log(cat.propertyIsEnumerable('sound'))//false
console.log(Object.getOwnPropertyNames(cat));//["name", "sound"]
🌰Object.keys()
只能获取自身的可枚举属性(无法获取原型链上的)
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.country='CN';
var Joe=new Person('Joe',24)
Object.defineProperty(Joe,'city',{
value: 'GZ',
enumerable:true
})
console.log(Object.keys(Joe));
console.log(Object.values(Joe));
console.log(Object.entries(Joe));
🌰 for...in
遍历对象自身的和原型链上的可枚举的属性。
let Joe = new Person();
Joe.name = 'Joe';
function Person(){}
Person.prototype._age = 24;
const for_in_keys = (()=>{
let keysArray=[];
return ()=>{
for (let key in Joe) {
keysArray.push(key)
}
return keysArray;
}
})()
console.log(for_in_keys());//["name", "_age"]
🌰遍历Symbol属性值
let sb=Symbol();
let a={name:'Joe'}
a[sb]='1'
console.log(a[sb]);
console.log({key:Object.keys(a),sym:Object.getOwnPropertySymbols(a),all:Reflect.ownKeys(a)});