JavaScript对象(Object)研究_04_getOwnPropertyNames、getOwnPropertySymbols、getPrototypeOf、groupBy、hasOwn
在JavaScript中,Object
构造函数提供了丰富的静态方法,用于操作和管理对象的属性和原型链。深入理解这些方法有助于我们更有效地编写和调试代码。本篇博客将详细介绍Object
的五个重要静态方法:getOwnPropertyNames
、getOwnPropertySymbols
、getPrototypeOf
、groupBy
、hasOwn
。通过基础介绍、语法说明、代码示例、返回值描述,以及扩展的知识点,我们将全面了解这些方法的用途、工作原理和注意事项。
一、Object.getOwnPropertyNames()
1. 基础介绍
Object.getOwnPropertyNames()
方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 属性)组成的数组。也就是说,它返回对象自身的所有属性名,包括不可枚举的属性,但不包括继承的属性和 Symbol 属性。
2. 语法
Object.getOwnPropertyNames(obj)
- obj:要返回其自身属性的对象。
3. 代码示例
示例1:获取对象的所有自身属性
const obj = {
a: 1,
b: 2
};
Object.defineProperty(obj, 'c', {
value: 3,
enumerable: false
});
const propNames = Object.getOwnPropertyNames(obj);
console.log(propNames);
// 输出: ['a', 'b', 'c']
示例2:获取数组的属性
const arr = ['a', 'b', 'c'];
const propNames = Object.getOwnPropertyNames(arr);
console.log(propNames);
// 输出: ['0', '1', '2', 'length']
4. 返回值描述
Object.getOwnPropertyNames()
方法返回一个数组,包含了对象自身所有属性名的字符串表示,包括不可枚举的属性,但不包括 Symbol 属性。
5. 扩展知识点
-
与
Object.keys()
的区别:Object.keys(obj)
:返回对象自身的可枚举属性名组成的数组,不包括不可枚举属性和 Symbol 属性。Object.getOwnPropertyNames(obj)
:返回对象自身的所有属性名,包括不可枚举属性,但不包括 Symbol 属性。
-
获取 Symbol 属性:
如果需要获取对象的 Symbol 属性名,可以使用
Object.getOwnPropertySymbols(obj)
方法。
6. 注意事项
- 不包括继承属性:该方法只返回对象自身的属性名,不包括从原型链继承的属性。
- 属性名为字符串:返回的属性名都是字符串类型,不包括 Symbol 类型的属性。
二、Object.getOwnPropertySymbols()
1. 基础介绍
Object.getOwnPropertySymbols()
方法返回一个由指定对象自身的所有 Symbol 属性键组成的数组。
2. 语法
Object.getOwnPropertySymbols(obj)
- obj:要返回其 Symbol 属性的对象。
3. 代码示例
示例1:获取对象的 Symbol 属性
const sym1 = Symbol('foo');
const sym2 = Symbol('bar');
const obj = {
[sym1]: 'value1',
[sym2]: 'value2',
normalProp: 'value3'
};
const symbols = Object.getOwnPropertySymbols(obj);
console.log(symbols);
// 输出: [Symbol(foo), Symbol(bar)]
for (const sym of symbols) {
console.log(`${sym.toString()}: ${obj[sym]}`);
}
// 输出:
// Symbol(foo): value1
// Symbol(bar): value2
4. 返回值描述
Object.getOwnPropertySymbols()
方法返回一个数组,包含了对象自身的所有 Symbol 属性键。
5. 扩展知识点
-
Symbol 属性的用途:
Symbol 类型的属性键通常用于定义对象的私有属性,避免与其他属性名发生冲突。
-
获取所有属性(包括 Symbol):
可以使用
Reflect.ownKeys(obj)
方法获取对象自身的所有属性键,包括字符串和 Symbol。const keys = Reflect.ownKeys(obj); console.log(keys); // 输出: ['normalProp', Symbol(foo), Symbol(bar)]
6. 注意事项
- 不包括字符串属性:该方法只返回 Symbol 属性,不包括字符串类型的属性名。
- 属性顺序不保证:返回的数组中,Symbol 属性的顺序不一定与添加的顺序一致。
三、Object.getPrototypeOf()
1. 基础介绍
Object.getPrototypeOf()
方法返回指定对象的原型(即内部[[Prototype]]属性的值)。这对于了解对象的继承关系和原型链非常有用。
2. 语法
Object.getPrototypeOf(obj)
- obj:需要获取其原型的对象。
3. 代码示例
示例1:获取对象的原型
const obj = {};
const proto = Object.getPrototypeOf(obj);
console.log(proto === Object.prototype); // 输出: true
示例2:自定义构造函数的原型
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, I'm ${this.name}`);
};
const alice = new Person('Alice');
const proto = Object.getPrototypeOf(alice);
console.log(proto === Person.prototype); // 输出: true
4. 返回值描述
Object.getPrototypeOf()
方法返回指定对象的原型。如果没有继承属性,则返回null
。
5. 扩展知识点
-
__proto__
属性:obj.__proto__
也可以用于获取对象的原型,但不推荐使用,因为__proto__
并不是所有环境都支持,且在规范中仅作为浏览器的一个历史遗留特性。 -
Object.setPrototypeOf()
方法:可以使用
Object.setPrototypeOf(obj, prototype)
方法设置对象的原型,但不推荐在性能敏感的代码中使用,因为修改对象的原型会影响性能。
6. 注意事项
-
不可用于原始类型:对于原始类型(如数字、字符串、布尔值),
Object.getPrototypeOf()
会抛出错误,除非先将其转换为对象。try { Object.getPrototypeOf(42); } catch (e) { console.log(e); // 输出TypeError: 42 is not an object } const numObj = new Number(42); const proto = Object.getPrototypeOf(numObj); console.log(proto === Number.prototype); // 输出: true
四、Object.groupBy()(分组)
1. 基础介绍
Object.groupBy()
静态方法根据提供的回调函数返回的字符串值对给定可迭代对象中的元素进行分组。返回的对象具有每个组的单独属性,其中包含组中的元素的数组。
-
实验性技术:
Object.groupBy()
目前是一个实验性技术,在将其用于生产环境之前,请仔细检查浏览器兼容性表格。 -
注意:在某些浏览器的某些版本中,此方法被实现为
Array.prototype.group()
方法。由于 Web 兼容性问题,它现在以静态方法实现。
2. 语法
Object.groupBy(items, callbackFn)
- items:一个将进行元素分组的可迭代对象(例如数组)。
- callbackFn:对可迭代对象中的每个元素执行的函数。它应该返回一个值,可以被强制转换成属性键(字符串或 Symbol),用于指示当前元素所属的分组。
3. 代码示例
示例1:根据属性分组对象数组
const inventory = [
{ name: '芦笋', type: '蔬菜', quantity: 5 },
{ name: '香蕉', type: '水果', quantity: 0 },
{ name: '山羊', type: '肉', quantity: 23 },
{ name: '樱桃', type: '水果', quantity: 5 },
{ name: '鱼', type: '肉', quantity: 22 },
];
const result = Object.groupBy(inventory, ({ type }) => type);
console.log(result);
/* 输出:
{
蔬菜: [
{ name: '芦笋', type: '蔬菜', quantity: 5 },
],
水果: [
{ name: '香蕉', type: '水果', quantity: 0 },
{ name: '樱桃', type: '水果', quantity: 5 }
],
肉: [
{ name: '山羊', type: '肉', quantity: 23 },
{ name: '鱼', type: '肉', quantity: 22 }
]
}
*/
在这个示例中,我们根据每个对象的type
属性的值对元素进行分组。箭头函数({ type }) => type
使用了参数的对象解构,直接获取type
属性的值作为分组的键。
示例2:根据数量分组
const result2 = Object.groupBy(inventory, ({ quantity }) => {
return quantity > 5 ? 'ok' : 'restock';
});
console.log(result2);
/* 输出:
{
restock: [
{ name: '芦笋', type: '蔬菜', quantity: 5 },
{ name: '香蕉', type: '水果', quantity: 0 },
{ name: '樱桃', type: '水果', quantity: 5 }
],
ok: [
{ name: '山羊', type: '肉', quantity: 23 },
{ name: '鱼', type: '肉', quantity: 22 }
]
}
*/
在这个示例中,我们根据quantity
的值将项目分为ok
或restock
组。
4. 返回值描述
Object.groupBy()
方法返回一个对象,其属性是分组的键,值是一个数组,包含属于该组的元素。返回的对象是一个具有null
原型的对象,避免了从Object.prototype
继承的属性干扰。
5. 扩展知识点
-
与
Map.groupBy()
的区别:当需要使用任意值作为键进行分组时,可以使用
Map.groupBy()
方法(也是实验性技术)。Object.groupBy()
只能使用字符串或 Symbol 作为键。 -
处理回调函数返回的键:
回调函数返回的值会被强制转换为字符串或 Symbol,作为返回对象的属性名。如果返回值不是字符串或 Symbol,将被转换为字符串。
6. 注意事项
-
实验性技术:由于
Object.groupBy()
是实验性的,在使用前需要确认环境是否支持。 -
浏览器兼容性:请参阅MDN 浏览器兼容性表格以获取更多信息。
-
Polyfill 实现:如果当前环境不支持
Object.groupBy()
,可以使用以下方式实现类似的功能:function groupBy(items, callbackFn) { const result = Object.create(null); for (const [index, item] of items.entries()) { const key = callbackFn(item, index); const groupKey = String(key); if (!result[groupKey]) { result[groupKey] = []; } result[groupKey].push(item); } return result; } const result = groupBy(inventory, ({ type }) => type); console.log(result);
五、Object.hasOwn()
1. 基础介绍
Object.hasOwn()
方法用于判断对象自身是否具有指定的属性。它是Object.prototype.hasOwnProperty()
的一个替代方法,避免了hasOwnProperty
可能被覆盖的问题。
2. 语法
Object.hasOwn(obj, prop)
- obj:要检查的对象。
- prop:要检查的属性名,可以是字符串或 Symbol。
3. 代码示例
示例1:检查对象自身的属性
const obj = {
a: 1
};
console.log(Object.hasOwn(obj, 'a')); // 输出: true
console.log(Object.hasOwn(obj, 'b')); // 输出: false
示例2:对象的原型链上的属性
const proto = { b: 2 };
const obj = Object.create(proto);
obj.a = 1;
console.log(Object.hasOwn(obj, 'a')); // 输出: true
console.log(Object.hasOwn(obj, 'b')); // 输出: false
4. 返回值描述
Object.hasOwn()
方法返回一个布尔值,表示对象自身是否具有指定的属性。
5. 扩展知识点
-
为什么使用
Object.hasOwn()
:-
安全性:
Object.prototype.hasOwnProperty
可能会被对象自身的同名属性覆盖,使用Object.hasOwn()
可以避免这种情况。const obj = { hasOwnProperty: function() { return false; }, a: 1 }; console.log(obj.hasOwnProperty('a')); // 输出: false console.log(Object.hasOwn(obj, 'a')); // 输出: true
-
-
与
in
操作符的区别:Object.hasOwn(obj, prop)
只检查对象自身的属性。prop in obj
会检查对象自身以及其原型链上的属性。
const proto = { b: 2 }; const obj = Object.create(proto); obj.a = 1; console.log(Object.hasOwn(obj, 'b')); // 输出: false console.log('b' in obj); // 输出: true
6. 注意事项
-
参数类型:
prop
可以是字符串或 Symbol,其他类型会被转换为字符串。console.log(Object.hasOwn(obj, 1)); // 等价于 Object.hasOwn(obj, '1')
-
浏览器支持:
Object.hasOwn()
是在 ECMAScript 2022 中引入的,使用前需要确认环境支持。
注意事项总结
Object.getOwnPropertyNames()
:返回对象自身的所有属性名,包括不可枚举属性,但不包括 Symbol 属性。返回值为字符串数组。Object.getOwnPropertySymbols()
:返回对象自身的所有 Symbol 属性键。返回值为 Symbol 数组。Object.getPrototypeOf()
:获取对象的原型。返回值为对象的原型,如果没有继承则返回null
。Object.groupBy()
:根据回调函数对可迭代对象的元素进行分组。返回值为一个具有null
原型的对象,键为分组键,值为包含分组元素的数组。需要注意环境支持和浏览器兼容性。Object.hasOwn()
:检查对象自身是否具有指定属性。返回值为布尔值。相比hasOwnProperty
,更加安全可靠。
参考资料: