js获取对象的属性

for...in

该方法一次访问一个对象及其原型链中所有可枚举的属性

1
2
3
4
let obj = {name:'june', age:'forever 18'}
for (let i in obj){
console.log(i)
}

Object.keys()

返回指定对象属性名的数组,顺序和常规循环获得的一样。

1
2
3
4
5
6
7
const obj = {
name: 'june',
age: '18',
gender: 'female'
}
console.log(Object.keys(obj));
//运行结果:["name", "age", "gender"]

该方法返回的是对象自己的可枚举的属性。

Object.keys() returns an array whose elements are strings corresponding to the enumerable properties found directly upon object. The ordering of the properties is the same as that given by looping over the properties of the object manually.

引用自mdn。
如果想要对象的所有属性,包括不可枚举的属性,使用 Object.getOwnPropertyNames()

注意:在es5中,如果传入这个方法的参数不是对象,比如一个原始类型,会引发TypeError错误。但在es6,非对象的参数会被强制转化为一个对象。

1
2
3
4
Object.keys('june');
// TypeError: 'june' is not an object (ES5 code)
Object.keys('june');
//["0", "1", "2", "3"]

兼容代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) {
Object.keys = (function() {
'use strict';
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;

return function(obj) {
if (typeof obj !== 'function' && (typeof obj !== 'object' || obj === null)) {
throw new TypeError('Object.keys called on non-object');
}

var result = [], prop, i;

for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop);
}
}

if (hasDontEnumBug) {
for (i = 0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) {
result.push(dontEnums[i]);
}
}
}
return result;
};
}());
}

Object.getOwnPropertyNames()

返回一个数组,数组的元素为对象自身属性名称的字符串,包括可枚举和不可枚举的属性,但不包括Symbol值作为名称的属性。
可枚举属性在数组中的顺序与 for...in 或者 Object.keys() 一致。但不可枚举的属性顺序未定义。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
let arr = ["June", "Lucy", "Sheery", "Alina"];
console.log(Object.getOwnPropertyNames(arr).sort());
// 运行结果:["0", "1", "2", "3", "length"]

// 类数组对象
let girls = { 0: "June", 1: "Lucy", 2: "Sheery", 3:"Alina"};
console.log(Object.getOwnPropertyNames(girls).sort());
// 运行结果:["0", "1", "2", "3"]

// 用Array.forEach输出属性名和属性值
Object.getOwnPropertyNames(girls).forEach(function(val, idx, array) {
console.log(val + " -> " + girls[val]);
});

// 不可枚举属性
let june = Object.create({}, {
get_skills: {
value: function() { return this.skills; },
enumerable: false
}
});

june.skills=["HTML", "CSS", "JavaSript", "Python", "Sql"];
console.log(Object.getOwnPropertyNames(june).sort());
//运行结果:["get_skills", "skills"]

总结:如果只需要获取可枚举属性,用Object.keys()或者for...in循环,这样还会获取原型链上的可枚举属性,不过可以使用hasOwnProperty()方法过滤掉。
或使用Object.getOwnPropertyNames()获得所有属性,再用Array.prototype.fiter()方法过滤。
提示:Object.getOwnPropertyNames()在ES5中如果参数不是原始对象类型,将抛出TypeError异常,ES6中,非对象参数会被强制转为对象。