一文搞懂!JavaScript中Object.getOwnPropertyNames()和Object.getOwnPropertySymbols()的硬核区别
在前端开发的江湖里,JavaScript就像是咱们工程师手里的瑞士军刀,各种对象操作技巧都是行走江湖的必备技能。今天咱们就来深挖两个超实用的API------Object.getOwnPropertyNames()
和Object.getOwnPropertySymbols()
,这俩兄弟看似功能相似,实则暗藏玄机。无论是刚入行的前端小白,还是身经百战的老司机,搞懂它们的区别,都能让你的代码功力更上一层楼,在解决对象属性遍历、数据处理等前端高频问题时游刃有余!
一、先认识认识这俩"兄弟"
在JavaScript的对象世界里,属性就像是对象的"家当"。而Object.getOwnPropertyNames()
和Object.getOwnPropertySymbols()
就是帮助我们清点这些"家当"的得力工具。但它们各有分工,就好比两个不同的仓库管理员,一个专门管理普通的"货物"(属性名),一个则负责看守特殊的"机密物资"(Symbol类型的属性)。
1. Object.getOwnPropertyNames()
这个方法就像是一个"普通属性大搜查官"。它的职责是把对象自身拥有的所有非Symbol类型的属性名都找出来,以数组的形式返回。注意,这里说的是对象自身的属性,不包括从原型链上继承来的属性。什么是自身属性呢?举个栗子:
javascript
// 创建一个简单的对象
const person = {
name: '小明', // 字符串类型的属性名
age: 25, // 数字类型的属性名
isStudent: false // 布尔类型的属性名
};
// 使用Object.getOwnPropertyNames()获取对象的属性名
const propertyNames = Object.getOwnPropertyNames(person);
console.log(propertyNames); // 输出: ["name", "age", "isStudent"]
在这段代码中,我们先创建了一个person
对象,它有三个属性。然后调用Object.getOwnPropertyNames()
,就把person
对象自身的三个属性名以数组的形式获取到了。这在处理对象数据结构,比如要展示对象所有可枚举属性时,就非常有用,也是前端开发中经常会遇到的场景。
2. Object.getOwnPropertySymbols()
Object.getOwnPropertySymbols()
则是一个"Symbol属性守护者"。它专门用来找出对象自身拥有的Symbol类型的属性,同样以数组形式返回。Symbol是ES6引入的一种新的原始数据类型,它最大的特点就是具有唯一性,常用于创建对象中那些不希望被轻易修改或覆盖的属性。咱们来看段代码:
javascript
// 创建一个Symbol
const hobbySymbol = Symbol('hobby');
// 创建一个对象,并添加一个Symbol类型的属性
const anotherPerson = {
name: '小红',
[hobbySymbol]: '阅读' // 使用Symbol作为属性名
};
// 使用Object.getOwnPropertySymbols()获取对象的Symbol属性
const symbolProperties = Object.getOwnPropertySymbols(anotherPerson);
console.log(symbolProperties); // 输出: [Symbol(hobby)]
这里我们先创建了一个hobbySymbol
的Symbol,然后在anotherPerson
对象中使用它作为属性名。最后调用Object.getOwnPropertySymbols()
,成功获取到了这个对象中唯一的Symbol类型属性。在实际的前端项目中,比如实现一些需要私有属性或者防止属性名冲突的场景,Symbol属性就派上大用场了,而Object.getOwnPropertySymbols()
就是获取这些特殊属性的关键方法。
二、深入剖析它们的区别
1. 返回的属性类型不同
这是二者最本质的区别。Object.getOwnPropertyNames()
只关注字符串、数字、布尔等非Symbol类型的属性名 ,就像它只认普通的"大路货"属性;而Object.getOwnPropertySymbols()
则只对Symbol类型的属性感兴趣,只"捡"那些特殊的、独一无二的"宝贝"属性。咱们再通过一个复杂点的例子来感受一下:
javascript
// 创建多个Symbol
const skillSymbol = Symbol('skill');
const petSymbol = Symbol('pet');
// 创建一个复杂对象
const complexPerson = {
name: '小刚',
age: 30,
[skillSymbol]: '编程',
[petSymbol]: '猫'
};
// 使用Object.getOwnPropertyNames()获取属性名
const names = Object.getOwnPropertyNames(complexPerson);
console.log(names); // 输出: ["name", "age"]
// 使用Object.getOwnPropertySymbols()获取Symbol属性
const symbols = Object.getOwnPropertySymbols(complexPerson);
console.log(symbols); // 输出: [Symbol(skill), Symbol(pet)]
在这个例子中,complexPerson
对象既有普通属性,又有Symbol属性。Object.getOwnPropertyNames()
只把普通属性名找了出来,而Object.getOwnPropertySymbols()
则准确地获取到了所有Symbol属性。这种属性类型的差异,决定了它们在不同业务场景下的应用。
2. 应用场景不同
Object.getOwnPropertyNames()
的常见场景:
- 数据展示与处理 :在前端开发中,经常需要把对象的数据展示到页面上。比如从后端接口获取到一个包含用户信息的对象,需要遍历对象的属性来生成HTML结构。这时候
Object.getOwnPropertyNames()
就能快速获取所有普通属性名,方便进行数据渲染。
javascript
// 假设从后端获取的用户数据对象
const userData = {
username: 'user123',
email: '[email protected]',
phone: '1234567890'
};
// 使用Object.getOwnPropertyNames()遍历属性并生成HTML
const propertyNames = Object.getOwnPropertyNames(userData);
let html = '<ul>';
propertyNames.forEach(name => {
html += `<li>${name}: ${userData[name]}</li>`;
});
html += '</ul>';
document.body.innerHTML = html;
这段代码通过Object.getOwnPropertyNames()
获取userData
对象的属性名,然后遍历生成HTML列表,将用户信息展示在页面上。
- 对象克隆与合并 :在进行对象克隆或者合并操作时,也需要获取对象自身的属性。比如实现一个浅克隆函数,就可以用
Object.getOwnPropertyNames()
获取属性名,然后逐个复制属性。
javascript
// 浅克隆函数
function shallowClone(obj) {
const clone = {};
const propertyNames = Object.getOwnPropertyNames(obj);
propertyNames.forEach(name => {
clone[name] = obj[name];
});
return clone;
}
const originalObject = {
key1: 'value1',
key2: 'value2'
};
const clonedObject = shallowClone(originalObject);
console.log(clonedObject); // 输出: { key1: 'value1', key2: 'value2' }
Object.getOwnPropertySymbols()
的常见场景:
- 私有属性的管理 :在JavaScript中,虽然没有真正意义上的私有属性,但可以通过Symbol来模拟私有属性。
Object.getOwnPropertySymbols()
可以用来获取这些私有属性,方便在类内部进行管理和操作。
javascript
const privatePropertySymbol = Symbol('privateProperty');
class MyClass {
constructor() {
this[privatePropertySymbol] = '这是私有属性';
}
getPrivateProperty() {
const symbols = Object.getOwnPropertySymbols(this);
for (const symbol of symbols) {
if (symbol === privatePropertySymbol) {
return this[symbol];
}
}
return null;
}
}
const myObj = new MyClass();
console.log(myObj.getPrivateProperty()); // 输出: 这是私有属性
在这个例子中,通过Symbol定义了一个私有属性,然后在类的方法中使用Object.getOwnPropertySymbols()
来获取并返回该私有属性的值。
- 防止属性名冲突 :在大型项目中,多个模块可能会向同一个对象添加属性,为了避免属性名冲突,可以使用Symbol作为属性名。
Object.getOwnPropertySymbols()
则用于获取这些特殊的属性,进行相应的处理。
3. 遍历行为不同
Object.getOwnPropertyNames()
获取到的属性名数组,在遍历的时候和普通数组遍历方式一样,可以使用for...of
、forEach
等方法。而Object.getOwnPropertySymbols()
返回的Symbol属性数组,由于Symbol的特殊性,在遍历和使用时需要注意一些细节。比如在和其他类型的属性一起处理时,需要分别获取和操作。
javascript
const combinedObject = {
regularProp: '普通属性',
[Symbol('symbolProp')]: 'Symbol属性'
};
// 获取普通属性名
const regularNames = Object.getOwnPropertyNames(combinedObject);
// 获取Symbol属性
const symbolProps = Object.getOwnPropertySymbols(combinedObject);
// 分别处理普通属性和Symbol属性
regularNames.forEach(name => {
console.log(`普通属性 ${name}: ${combinedObject[name]}`);
});
symbolProps.forEach(symbol => {
console.log(`Symbol属性 ${symbol}: ${combinedObject[symbol]}`);
});
这段代码分别获取了对象的普通属性名和Symbol属性,并进行了遍历和输出,展示了二者在遍历处理上的不同。
四、总结
Object.getOwnPropertyNames()
和Object.getOwnPropertySymbols()
虽然都是用来获取对象属性的方法,但它们各司其职,有着明显的区别。Object.getOwnPropertyNames()
专注于普通非Symbol类型的属性名,在数据展示、对象克隆等常见场景中发挥重要作用;而Object.getOwnPropertySymbols()
则守护着Symbol类型的特殊属性,在私有属性管理、防止属性名冲突等方面大显身手。作为前端工程师,熟练掌握这两个方法,能让我们在处理对象属性时更加得心应手,无论是解决实际项目中的问题,还是应对前端面试中的高频考点,都能轻松应对。希望通过本文的详细讲解,大家对这两个方法有了更深入的理解,赶紧在实际项目中试试吧!