对象字面量增强(Object Literal Enhancements)
概述
ES6 对对象字面量进行了多项增强,包括属性简写、方法简写、计算属性名等。
属性简写
基本用法
// 传统方式
const name = 'John';
const age = 25;
const person = {
name: name,
age: age
};
// 属性简写(属性名和变量名相同时)
const person2 = { name, age };
console.log(person2); // { name: 'John', age: 25 }
实际应用
function createUser(name, email, age) {
return { name, email, age };
}
const user = createUser('John', 'john@example.com', 25);
console.log(user); // { name: 'John', email: 'john@example.com', age: 25 }
方法简写
基本用法
// 传统方式
const person = {
name: 'John',
greet: function() {
return `Hello, ${this.name}!`;
}
};
// 方法简写
const person2 = {
name: 'John',
greet() {
return `Hello, ${this.name}!`;
}
};
// 箭头函数(注意 this 绑定)
const person3 = {
name: 'John',
greet: () => {
return `Hello, ${this.name}!`; // this 不指向 person3
}
};
简写方法的特性
const obj = {
// 简写方法可以使用 super
parentMethod() {
return 'parent';
},
// 简写方法不能用作构造函数
myMethod() {
// new this.myMethod() 会报错
}
};
计算属性名
基本用法
// 传统方式
const propName = 'name';
const person = {};
person[propName] = 'John';
// 计算属性名
const person2 = {
[propName]: 'John'
};
console.log(person2.name); // 'John'
表达式作为属性名
const prefix = 'user';
const suffix = 'Id';
const obj = {
[`${prefix}_${suffix}`]: 123,
[prefix + '_' + suffix]: 456,
['hello' + 'World']: 'test'
};
console.log(obj.user_Id); // 123
console.log(obj.helloWorld); // 'test'
方法名计算
const methodName = 'sayHello';
const person = {
name: 'John',
[methodName]() {
return `Hello, ${this.name}!`;
}
};
console.log(person.sayHello()); // Hello, John!
属性名表达式
动态属性名
function createObject(key, value) {
return {
[key]: value
};
}
const obj = createObject('status', 'active');
console.log(obj); // { status: 'active' }
Symbol 作为属性名
const mySymbol = Symbol('mySymbol');
const obj = {
[mySymbol]: 'symbol value',
regularProperty: 'regular value'
};
console.log(obj[mySymbol]); // 'symbol value'
新增方法
Object.is()
比较两个值是否严格相等,与 === 类似,但处理 NaN 和 +0/-0 不同:
// 与 === 的区别
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true
console.log(+0 === -0); // true
console.log(Object.is(+0, -0)); // false
// 其他情况与 === 相同
console.log(Object.is(1, 1)); // true
console.log(Object.is('a', 'a')); // true
console.log(Object.is({}, {})); // false
Object.assign()
将源对象的可枚举属性复制到目标对象:
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3, a: 4 };
const result = Object.assign(target, source1, source2);
console.log(result); // { a: 4, b: 2, c: 3 }
console.log(target === result); // true(target 被修改)
// 浅拷贝
const copy = Object.assign({}, source1);
注意事项
// 只拷贝可枚举属性
const obj = {};
Object.defineProperties(obj, {
visible: { value: 1, enumerable: true },
hidden: { value: 2, enumerable: false }
});
const copy = Object.assign({}, obj);
console.log(copy); // { visible: 1 }(hidden 不会被拷贝)
// Symbol 属性也会被拷贝
const sym = Symbol('test');
const source = { [sym]: 'value' };
const copy2 = Object.assign({}, source);
console.log(copy2[sym]); // 'value'
Object.keys()、Object.values()、Object.entries()
const person = {
name: 'John',
age: 25,
city: 'New York'
};
// 获取所有键
console.log(Object.keys(person)); // ['name', 'age', 'city']
// 获取所有值
console.log(Object.values(person)); // ['John', 25, 'New York']
// 获取键值对
console.log(Object.entries(person));
// [['name', 'John'], ['age', 25], ['city', 'New York']]
// 遍历对象
Object.entries(person).forEach(([key, value]) => {
console.log(`${key}: ${value}`);
});
// 转换为 Map
const map = new Map(Object.entries(person));
console.log(map); // Map { 'name' => 'John', 'age' => 25, 'city' => 'New York' }
实际应用示例
1. API 响应处理
function processUserResponse(data) {
const { id, name, email, avatar } = data;
return {
id,
name,
email,
avatar: avatar || '/default-avatar.png',
displayName: name.toUpperCase(),
getInitials() {
return name.split(' ').map(n => n[0]).join('');
}
};
}
2. 配置对象
function createConfig(env) {
const base = {
apiUrl: 'https://api.example.com',
timeout: 5000
};
const configs = {
development: { debug: true, logLevel: 'verbose' },
production: { debug: false, logLevel: 'error' },
test: { debug: true, logLevel: 'silent' }
};
return {
...base,
...configs[env],
[`${env}Mode`]: true
};
}
const config = createConfig('development');
// { apiUrl: '...', timeout: 5000, debug: true, logLevel: 'verbose', developmentMode: true }
3. 动态对象创建
function createEntity(type, data) {
const timestamp = Date.now();
return {
type,
[`${type}Id`]: data.id,
...data,
createdAt: timestamp,
updatedAt: timestamp,
[`get${type.charAt(0).toUpperCase() + type.slice(1)}Info`]() {
return `${type}: ${data.name}`;
}
};
}
const user = createEntity('user', { id: 123, name: 'John' });
console.log(user.userId); // 123
console.log(user.getUserInfo()); // "user: John"
4. 状态管理
function createReducer(initialState, handlers) {
return function reducer(state = initialState, action) {
const handler = handlers[action.type];
return handler ? handler(state, action) : state;
};
}
const userReducer = createReducer(
{ users: [], loading: false },
{
FETCH_USERS: (state) => ({ ...state, loading: true }),
FETCH_USERS_SUCCESS: (state, action) => ({
...state,
loading: false,
users: action.payload
}),
FETCH_USERS_ERROR: (state, action) => ({
...state,
loading: false,
error: action.error
})
}
);
最佳实践
- 使用属性简写:当属性名和变量名相同时
- 使用方法简写:定义对象方法时
- 合理使用计算属性名:处理动态属性
- 注意 Object.assign() 的浅拷贝特性
- 使用 Object.entries() 遍历对象
// 好的做法
const createUser = (name, age) => ({ name, age });
const actions = {
increment: (state) => ({ ...state, count: state.count + 1 }),
decrement: (state) => ({ ...state, count: state.count - 1 }),
reset: () => ({ count: 0 })
};
// 避免
const bad = {
name: name,
age: age,
greet: function() { return 'Hello'; }
};
参考
目录