广告

JavaScript 获取对象属性值的完整方法详解:从访问到遍历的实战技巧

基础访问对象属性的方法

点记法与方括号表示法

点记法是最直观的属性访问方式,写法为 obj.prop,适用于属性名为合法标识符且不包含特殊字符的情况。它的语义清晰、可读性高,通常在热路径访问中表现更好。方括号表示法 obj['prop'] 则在属性名以变量形式传入或包含空格、连字符等无法用点记法访问的场景下非常有用。两者都只访问对象的自有属性或原型链上的可枚举属性。

在实际使用中,建议先尝试 点记法,需动态确定属性名或属性名不符合标识符规范时再使用 方括号表示法。下面的示例展示两种访问方式在同一对象上的效果、以及动态属性名的实际用途。

const obj = { name: 'Alice', 'user-id': 42 };console.log(obj.name);       // Alice
console.log(obj['name']);    // Alice
console.log(obj['user-id']); // 42// 动态属性名
const key = 'name';
console.log(obj[key]);       // Alice

可选链与空值合并

在深层对象访问时,直接访问链式属性可能遇到 undefined,从而抛出类型错误。可选链(?.)允许在链路中的任意一环为 null/undefined 时安全返回 undefined,避免显式的空值判断。空值合并(??)用于在值为 null 或 undefined 时提供默认值,提升容错能力。

结合示例讲解,展示如何在大对象中进行安全访问并设置默认值:

const data = { user: { profile: { name: 'Bob' } } };console.log(data?.user?.profile?.name); // 'Bob'
console.log(data?.profile?.age ?? 18);   // 18

对象自身属性与继承属性

区分自身属性与原型链属性

在 JavaScript 中,for...in会遍历对象自身的可枚举属性以及原型链上的同类属性;而 Object.keysObject.getOwnPropertyNames 只返回对象自身的属性。若需要严格判断某属性是否属于对象自身,可以使用 hasOwnProperty,避免检索到来自原型链的属性。

下面的示例说明如何区分自有属性和继承属性,帮助开发者在遍历时做出过滤决策。

const proto = { inherited: 1 };
const obj = Object.create(proto);
obj.own = 2;// 遍历包含原型链的可枚举属性
for (const k in obj) {console.log(k); // 'own' 和 'inherited'
}// 仅自身属性
console.log(Object.keys(obj)); // ['own']
console.log('own' in obj);      // true
console.log(obj.hasOwnProperty('own')); // true
console.log(obj.hasOwnProperty('inherited')); // false

判断属性存在性的方法

判断属性是否存在可通过 in 运算符(检查原型链)以及 hasOwnProperty(仅检查自身属性)。理解二者的差异有助于避免误判。

示例帮助梳理两者的行为差异:

const o = { a: 1 };
console.log('a' in o); // true
console.log('toString' in o); // true,来自 Object.prototype
console.log(o.hasOwnProperty('a')); // true
console.log(o.hasOwnProperty('toString')); // false

属性描述符与只读/不可枚举

属性描述符与获取

通过 Object.getOwnPropertyDescriptor 可以获取指定自有属性的描述符,描述符包含 valuewritableenumerableconfigurable,以及 getset。描述符能帮助判断属性是数据属性还是访问器属性,也能看出属性是否可写、可枚举或可重新配置。

以下例子演示如何读取描述符并分析属性的可写性与枚举性:

const obj = {};
Object.defineProperty(obj, 'fixed', {value: 42,writable: false,enumerable: true,configurable: false
});
const d = Object.getOwnPropertyDescriptor(obj, 'fixed');
console.log(d.value); // 42
console.log(d.writable); // false

不可枚举属性的处理

不可枚举属性不会出现在 Object.keysfor...in 的遍历结果中,但仍然存在于对象中。为全面了解对象结构,可以利用 Object.getOwnPropertyNamesReflect.ownKeys 来获取所有自有属性,包括不可枚举和符号属性。

示例展示如何同时查看可枚举与不可枚举的自有属性:

Object.defineProperty(obj, '_secret', {value: 'hidden',enumerable: false
});
console.log(Object.keys(obj)); // ['fixed']
console.log(Object.getOwnPropertyNames(obj)); // ['fixed', '_secret']
console.log(Reflect.ownKeys(obj)); // ['fixed', '_secret']

深度遍历对象属性

路径获取的实现方式

在复杂对象中,按路径获取深层属性是一类常见需求。通过将路径按点号分割,再逐层访问,可以实现一个通用的路径取值函数。可选链让中间链路为 undefined 时不会抛错,直接返回 undefined。

JavaScript 获取对象属性值的完整方法详解:从访问到遍历的实战技巧

下面给出一个简单的路径获取实现,支持 name.first、address.city 等形式:

function getByPath(obj, path) {return path.split('.').reduce((o, key) => (o ? o[key] : undefined), obj);
}
const data = { user: { profile: { name: 'Alice' } } };
console.log(getByPath(data, 'user.profile.name')); // 'Alice'

递归遍历并收集所有属性值

如果需要把对象展开成键路径与对应值的集合,可通过递归遍历实现。需要明确遍历范围(自有属性或包含原型链)以及对循环引用的处理策略以避免无限循环。

以下示例演示在自有属性范围内的递归遍历,返回一个包含路径及对应值的数组:

function enumerate(obj, path = '') {const out = [];for (const key of Object.getOwnPropertyNames(obj)) {const value = obj[key];const p = path ? path + '.' + key : key;out.push([p, value]);if (value && typeof value === 'object') {out.push(...enumerate(value, p));}}return out;
}
const o = { a: { b: 1 }, c: 2 };
console.log(enumerate(o));

获取对象属性值的常用工具方法

ownKeys、keys、values、entries 的区别

Object.keys 只返回对象自有且可枚举的属性名;Object.getOwnPropertyNames 返回自有属性名(包括不可枚举的);Reflect.ownKeys 则返回自有属性名(包括符号属性)。

结合 Object.valuesObject.entries,可以方便地获取值列表或键值对列表,利于快速遍历与映射处理。

const obj = { a: 1, b: 2 };
console.log(Object.keys(obj)); // ['a', 'b']
console.log(Object.values(obj)); // [1, 2]
console.log(Object.entries(obj)); // [['a', 1], ['b', 2]]
console.log(Reflect.ownKeys(obj)); // ['a', 'b']

遍历数组与类数组对象

数组属性的特殊性

数组不仅是对象,还具有 length 属性与基于数字索引的自有属性。通常使用 Array.isArray 判断类型,并结合 forEachfor...of、以及传统的 for 循环来遍历。

下面的示例演示对数组的常规遍历与对长度的访问:

const arr = [1, 2, 3];
arr.forEach((v, i) => console.log(i, v)); // 0 1 \n 1 2 \n 2 3
console.log(arr.length); // 3

从对象角度遍历类数组对象

类数组对象,如 argumentsNodeList,虽然没有严格的数组方法,但可以通过 Object.keys 获取索引列表,再按下标访问对应值进行遍历。这个思路对不少前端场景很实用。

function show() {for (let i = 0; i < arguments.length; i++) {console.log(arguments[i]);}
}
show('a', 'b', 'c');

性能与最佳实践

访问方式的性能差异

点记法在多数引擎中更易被优化,通常比方括号表示法略快,且代码可读性更好。但当属性名在运行时动态决定时,必须使用 方括号表示法。在热路径中避免在循环内频繁创建新的对象或执行复杂的计算以提升访问性能。

在涉及深层属性时,使用 可选链可以减少空值检查的样板代码,但某些旧浏览器需要转译,注意兼容性。

const obj = { a: { b: { c: 1 } } };
console.log(obj.a?.b?.c); // 1

广告