获取对象不同类型属性的相关方法
一、对象属性理解
比如:数组中的length属性,描述符对象enumerable值为false,隐式属性。
看下正常的数组和对象的属性:
var arr = ["a", true, 3]
var obj = {
name: "zhu",
age: 24
}
console.log(arr)
console.log(obj)
二、关于遍历
1、for...
in循环(自身显式的属性,意外的获取了原型链上的属性)
只遍历显式属性和原型链上的显式属性, 当然也可以遍历数组。
var sym = Symbol("foo");
var arr = ["a", true, 3];
var obj = {
name: "zhu",
age: 24,
[sym]: "symbol-foo",
[Symbol("bar")]: "symbol-bar"
}
//age为隐式属性
Object.defineProperty(obj, "age", {
enumerable: false
})
//原型上的属性
obj.__proto__ = {
fa: "father"
}
var objStack = [];
var arrStack = [];
for(var prop in obj){
objStack.push(prop)
}
for(var i in arr){
arrStack.push(i)
}
console.log(objStack)
console.log(arrStack)
["name", "fa"]
["0", "1", "2"]
所以我们在使用for in 遍历的时候,防止遍历到原型链上的属性,我们会用hasOwnProperty方法来判断是不是对象本身的属性
console.log(obj.hasOwnProperty("fa"))
而 in 方法可以判断属性是不是对象原型及原型链上的属性
console.log("fa" in obj )
2、for...of循环
只遍历iterable类型的值,且处理的是iterable的值,而非属性或键;对象不是iterable类型
var arrStack = [];
var arr = ["a", true, 3, sym, Symbol("bar")];
for(var i of arr){
arrStack.push(i)
}
console.log(arrStack) //["a", true, 3, Symbol(foo), Symbol(bar)]
3、Object.keys()方法(自身显式的属性)
返回指定对象自身可枚举属性名称组成的数组。——兼容性IE9,ES5方法,还不会处理Symbol属性
var sym = Symbol("foo");
var arr = ["a", true, 3];
var obj = {
name: "zhu",
age: 24,
[sym]: "symbol-foo",
[Symbol("bar")]: "symbol-bar"
}
//age为隐式属性
Object.defineProperty(obj, "age", {
enumerable: false
})
//原型上的属性
obj.__proto__ = {
fa: "father"
}
console.log(Object.keys(obj)) //["name"]
console.log(Object.keys(arr)) //["0", "1", "2"]
4、Object.getOwnPropertyNames()方法、兼容性ES5 IE9——自身可枚举的和不可枚举的属性——ES5方法,不处理Symbol属性
返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。即获取对象自身的所有属性,不包含Symbol属性。
即自身显式的和隐式的属性
var sym = Symbol("foo");
var arr = ["a", true, 3];
var obj = {
name: "zhu",
age: 24,
[sym]: "symbol-foo",
[Symbol("bar")]: "symbol-bar"
}
//age为隐式属性
Object.defineProperty(obj, "age", {
enumerable: false
})
//原型上的属性
obj.__proto__ = {
fa: "father"
}
console.log(Object.getOwnPropertyNames(obj)) //["name", "age"]
console.log(Object.getOwnPropertyNames(arr)) //["0", "1", "2", "length"]
该数组对元素是 obj
自身拥有的枚举或不可枚举属性名称字符串。 数组中枚举属性的顺序与通过 for...in
循环(或 Object.keys
)迭代该对象属性时一致。数组中不可枚举属性的顺序未定义。
数组:数组的顺序 (不可枚举的属性位定义顺序——跟对象属性顺序一样)
var arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort()); ["0", "1", "2", "length"]
类数组:
function foo(){
console.log(arguments);
console.log(Object.getOwnPropertyNames(arguments))
}
foo("zhu",true,3,5);
结果:
对象:
var my_obj = Object.create({}, {
getFoo: {
value: function() { return this.foo; },
enumerable: false
}
});
my_obj.foo = 1;
console.log(Object.getOwnPropertyNames(my_obj).sort()); ["foo", "getFoo"]
如果你只要获取到可枚举属性,查看Object.keys
或用for...in
循环(还会获取到原型链上的可枚举属性,不过可以使用hasOwnProperty()
方法过滤掉)
5、Object.getOwnPropertySymbols()方法——自身Symbol属性,ES6 Edge12方法返回一个给定对象自身的所有 Symbol 属性的数组。——ES6方法,专门处理Symbol属性
获取对象自身的Symbol属性
var sym = Symbol("foo");
var arr = ["a", true, 3];
var obj = {
name: "zhu",
age: 24,
[sym]: "symbol-foo",
[Symbol("bar")]: "symbol-bar"
}
//age为隐式属性
Object.defineProperty(obj, "age", {
enumerable: false
})
//原型上的属性
obj.__proto__ = {
fa: "father"
}
console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(foo), Symbol(bar)]
console.log(Object.getOwnPropertySymbols(arr)) //[]
与Object.getOwnPropertyNames()
类似,您可以将给定对象的所有符号属性作为 Symbol 数组获取。 请注意,Object.getOwnPropertyNames()
本身不包含对象的 Symbol 属性,只包含字符串属性。因为所有的对象在初始化的时候不会包含任何的 Symbol,除非你在对象上赋值了 Symbol 否则Object.getOwnPropertySymbols()
只会返回一个空的数组。
var obj = {};
var a = Symbol("a");
var b = Symbol.for("b");
obj[a] = "localSymbol";
obj[b] = "globalSymbol";
var objectSymbols = Object.getOwnPropertySymbols(obj);
console.log(objectSymbols.length); // 2
console.log(objectSymbols) // [Symbol(a), Symbol(b)]
console.log(objectSymbols[0]) // Symbol(a)
6、Object.values
Object.values()
方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for...in
循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。
Object.values()
返回一个数组,其元素是在对象上找到的可枚举属性值。属性的顺序与通过手动循环对象的属性值所给出的顺序相同。
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.values(obj)); // ['a', 'b', 'c']
兼容性不是很好,Edge14 Chrome54,可以根据keys方法实现一个polyfill
if (!Object.values) Object.values = function(obj) {
if (obj !== Object(obj))
throw new TypeError('Object.values called on a non-object');
var val=[],key;
for (key in obj) {
if (Object.prototype.hasOwnProperty.call(obj,key)) {
val.push(obj[key]);
}
}
return val;
}
7、Object.entries
Object.entries()
方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in
循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。
返回值:给定对象自身可枚举属性的键值对数组。
Object.entries()
返回一个数组,其元素是与直接在object
上找到的可枚举属性键值对相对应的数组。属性的顺序与通过手动循环对象的属性值所给出的顺序相同。
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
object对象转Map对象
var obj = { foo: "bar", baz: 42 };
var map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }
兼容性:Edge14 Chrome54,兼容性不是很好,可以通过keys方法来实现一个polyfill:
if (!Object.entries)
Object.entries = function( obj ){
var ownProps = Object.keys( obj ),
i = ownProps.length,
resArray = new Array(i); // preallocate the Array
while (i--)
resArray[i] = [ownProps[i], obj[ownProps[i]]];
return resArray;
}
若想支持IE8,替换上面Object.keys
三、总结
(1)for in获取对象的显式属性,因为是早期版本,也会获取原型链上的显式属性
(2)Object.keys() ES5的方法,对上面方法进行优化,只获取对象本身的显式属性,不考虑隐式属性和Symbol属性,因为Symbol属性是ES6新增的。
(3)Object.getOwnPropertyNames()方法,ES5方法,获取对象自身显式的和隐式的属性,不考虑Symbol属性,因为Symbol属性是ES6新增的。
(4)Object.getOwnPropertySymbols()方法,ES6方法,获取对象自身的Symbol属性。专门获取对象自身的Symbol属性。
(5)Object.values() 和 Object.entries()方法,兼容性Edge14 Chrome54兼容性不好,可以通过Object.keys()方法来做兼容