对象属性分类
对于属性遍历而言,可以将对象属性分为是否可枚举、是否为继承 两种
let ary = ['a', 'b', 'c']
在 ary
数组中,可枚举属性是对应的索引 0, 1, 2
,不可枚举的是 length
对象属性配置
对象中,属性是否可枚举可以通过 Object.defineProperty
设定
class Car { // 创建类
constructor(brand, model, color) {
this.brand = brand
this.model = model
this.color = color
}
}
let mycar = new Car('Tesla', 'model 3', 'red') // 没有的话 new 一个就好啦
Object.defineProperty(mycar ,"color",{
value: "red",
enumerable: false, //是否可枚举, 默认值 false
configurable: false, //是否可配置,默认值 false
writable: false, //没有 writable 使用默认值 false
});
对象创建完成,在控制台内通过颜色可以判断不可枚举属性,但作为一个严谨的程序员,当然需要更科学的办法啦
可枚举属性
Object.keys(o)
按顺序遍历返回一个数组,其包含对象 o 自身(不包括原型)的所有可枚举属性的名称
Object.keys(mycar)
// ["brand", "model"]
for...in循环
该方法会依次访问一个对象及其原型链中所有可枚举的属性,就当前对象而言,效果较Object.keys(o) 相同
for (let i in my car) {
console.log(i)
}
// brand
// model
但如果继承的原型链上已有可枚举属性,原型上的 'foo'
也被遍历进来了
mycar.__proto__.foo = 'foo'
for (let i in mycar) {
console.log(i)
}
// brand
// model
// foo
Object.keys(mycar)
// ["brand", "model"]
所以得再过滤下,使用 hasOwnProperty
过滤继承属性,返回布尔值
for(let i in mycar){
// 此处可以使用 mycar.hasOwnProperty(i),
// 以安全的角度看用 Object.prototype.hasOwnProperty.call(mycar,i)
if(Object.prototype.hasOwnProperty.call(mycar,i)){
console.log(i)
}
}
// brand
// model
所有属性
Object.getOwnPropertyNames(o)
该方法返回一个数组,其包含对象 o 所有自有的属性(无论是否可枚举)的名称
mycar.__proto__.foo = 'foo'
Object.getOwnPropertyNames( mycar )
// ["brand", "model", "color"]
不可枚举属性
那既然可枚举和全部自有属性都有办法获取,要获取不可枚举属性就简单了
mycar.__proto__.foo = 'foo'
Object.getOwnPropertyNames(mycar).filter(val =>
!Object.keys(mycar).includes(val)
)
// ["color"]
遍历顺序
值得注意的是,Object.keys()
遍历顺序对不同属性类型时,先后顺序不同
let a = {'zz': 3, 3: 99, 1: 100, 'bb': 0}
//["1", "3", "zz", "bb"]
引用 MDN 中说明:
一个对象的属性名可以是任何有效的 JavaScript 字符串,或者可以被转换为字符串的任何类型,包括空字符串
也就是说,对象的所有属性都会通过转换变化为字符串,而由数字转过来字符串排序优先(此处略有疑问)而 for...in循环
遍历顺序与 Object.keys()
一致
// 同时创建多个变量
let myObj = new Object(),
str = "myString",
rand = Math.random(),
obj = new Object(),
num1 = 23,
num2 = 99,
ary = [1,2];
myObj.type = "Dot syntax";
myObj["date created"] = "String with space";
myObj[str] = "String value";
myObj[rand] = "Random Number";
myObj[obj] = "Object";
myObj[ary] = 'here is a ary'
myObj[num2] = 'here is a number_2'
myObj[""] = "Even an empty string";
myObj[num1] = 'here is a number_1'
for(let i in myObj){console.log(typeof i,' --- ', i, ' --- ',myObj[i])}
// 去下图...
小结
-
遍历自有属性:
- 可枚举:
-
Object.keys(o)
遍历 对象o
上的所有可枚举自有属性 -
for...in
遍历对象o
上所有自有属性(包括继承属性)
-
- 可枚举 + 不可枚举:
-
Object.getOwnPropertyNames(o)
遍历对象o
上所有自有属性(无论是否可枚举)
-
- 不可枚举:
- 通过
Object.getOwnPropertyNames(o)
获取所有自有属性,在通过Object.keys(mycar)
获取 自有可枚举属性,在使用filter
过滤
- 通过
- 可枚举:
遍历顺序:以属性设定时顺序为准,数字例外优先排序(仅参考)
- 判断是否属于自有属性(返回布尔值):
- 普通做法
mycar.hasOwnProperty(i)
- 更安全的做法
Object.prototype.hasOwnProperty.call(mycar,i)
- 普通做法
统计表
源自 MDN ,关于属性的 枚举,继承 统计表