对象解构与扩展

对象解构赋值

解构赋值可以从对象中提取值并赋给变量。

基本解构

const person = {
    name: "东巴文",
    age: 1,
    city: "北京"
};

// 基本解构
const { name, age, city } = person;
console.log(name);  // "东巴文"
console.log(age);   // 1
console.log(city);  // "北京"

变量重命名

const person = {
    name: "东巴文",
    age: 1
};

// 重命名变量
const { name: userName, age: userAge } = person;
console.log(userName);  // "东巴文"
console.log(userAge);   // 1

默认值

当属性不存在或为undefined时,使用默认值。

基本用法

const person = {
    name: "东巴文",
    age: undefined
};

// 默认值
const { name, age = 0, city = "未知" } = person;
console.log(name);  // "东巴文"
console.log(age);   // 0(undefined使用默认值)
console.log(city);  // "未知"(不存在使用默认值)

与重命名配合

const person = {
    name: "东巴文"
};

// 重命名 + 默认值
const { name: userName = "匿名", age: userAge = 0 } = person;
console.log(userName);  // "东巴文"
console.log(userAge);   // 0

函数参数默认值

function createUser({ name = "匿名", age = 0, city = "未知" } = {}) {
    return { name, age, city };
}

createUser();  // { name: "匿名", age: 0, city: "未知" }
createUser({ name: "东巴文" });  // { name: "东巴文", age: 0, city: "未知" }

嵌套解构

可以解构嵌套的对象。

基本嵌套解构

const person = {
    name: "东巴文",
    address: {
        city: "北京",
        district: "朝阳"
    },
    contacts: {
        email: "test@example.com",
        phone: "1234567890"
    }
};

// 嵌套解构
const { 
    name,
    address: { city, district },
    contacts: { email }
} = person;

console.log(name);      // "东巴文"
console.log(city);      // "北京"
console.log(district);  // "朝阳"
console.log(email);     // "test@example.com"

深层嵌套

const data = {
    user: {
        profile: {
            personal: {
                name: "东巴文",
                age: 1
            }
        }
    }
};

const { user: { profile: { personal: { name, age } } } } = data;
console.log(name);  // "东巴文"
console.log(age);   // 1

数组与对象混合解构

const data = {
    users: [
        { name: "东巴文", age: 1 },
        { name: "张三", age: 20 }
    ]
};

const { users: [first, second] } = data;
console.log(first);   // { name: "东巴文", age: 1 }
console.log(second);  // { name: "张三", age: 20 }

const { users: [{ name: firstName }] } = data;
console.log(firstName);  // "东巴文"

对象展开运算符

展开运算符(...)可以展开对象属性。

基本用法

const person = {
    name: "东巴文",
    age: 1
};

// 展开对象
const personCopy = { ...person };
console.log(personCopy);  // { name: "东巴文", age: 1 }

// 添加属性
const extended = { ...person, city: "北京" };
console.log(extended);  // { name: "东巴文", age: 1, city: "北京" }

合并对象

const defaults = {
    theme: "light",
    language: "zh-CN",
    notifications: true
};

const userSettings = {
    theme: "dark",
    language: "en-US"
};

// 合并(后面的覆盖前面的)
const settings = { ...defaults, ...userSettings };
console.log(settings);
// { theme: "dark", language: "en-US", notifications: true }

覆盖属性

const person = {
    name: "东巴文",
    age: 1
};

// 覆盖属性
const updated = { ...person, age: 2 };
console.log(updated);  // { name: "东巴文", age: 2 }

// 注意顺序
const wrong = { age: 2, ...person };
console.log(wrong);  // { age: 1, name: "东巴文" }(被覆盖回去了)

浅拷贝

const person = {
    name: "东巴文",
    address: {
        city: "北京"
    }
};

const copy = { ...person };

// 浅拷贝:嵌套对象是引用
copy.address.city = "上海";
console.log(person.address.city);  // "上海"

对象Rest属性

Rest属性收集剩余的属性。

基本用法

const person = {
    name: "东巴文",
    age: 1,
    city: "北京",
    country: "中国"
};

// 收集剩余属性
const { name, ...rest } = person;
console.log(name);  // "东巴文"
console.log(rest);  // { age: 1, city: "北京", country: "中国" }

排除属性

const person = {
    name: "东巴文",
    age: 1,
    city: "北京",
    password: "secret"
};

// 排除敏感属性
const { password, ...safePerson } = person;
console.log(safePerson);  // { name: "东巴文", age: 1, city: "北京" }

函数参数

function createUser({ name, age, ...rest }) {
    return {
        name,
        age,
        metadata: rest
    };
}

const user = createUser({
    name: "东巴文",
    age: 1,
    city: "北京",
    role: "admin"
});

console.log(user);
// { name: "东巴文", age: 1, metadata: { city: "北京", role: "admin" } }

Object.assign

Object.assign用于合并对象属性。

基本用法

const target = { a: 1, b: 2 };
const source = { b: 3, c: 4 };

// 合并到target
const result = Object.assign(target, source);
console.log(result);  // { a: 1, b: 3, c: 4 }
console.log(target);  // { a: 1, b: 3, c: 4 }(target被修改)

// 不修改原对象
const result2 = Object.assign({}, target, source);

多个源对象

const defaults = { a: 1, b: 2 };
const options1 = { b: 3, c: 4 };
const options2 = { c: 5, d: 6 };

const result = Object.assign({}, defaults, options1, options2);
console.log(result);  // { a: 1, b: 3, c: 5, d: 6 }

克隆对象

const original = { name: "东巴文" };

// 浅克隆
const clone = Object.assign({}, original);
clone.name = "JavaScript";
console.log(original.name);  // "东巴文"

Object.assign vs 展开运算符

// 两者都是浅拷贝
const obj = { a: 1, b: { c: 2 } };

const copy1 = Object.assign({}, obj);
const copy2 = { ...obj };

// 区别:Object.assign会触发setter
const target = {
    set name(value) {
        console.log("设置name:", value);
    }
};

Object.assign(target, { name: "东巴文" });  // 触发setter
// { ...target, name: "东巴文" }  // 不触发setter

Object.entries

Object.entries返回对象的可枚举键值对数组。

基本用法

const person = {
    name: "东巴文",
    age: 1,
    city: "北京"
};

const entries = Object.entries(person);
console.log(entries);
// [["name", "东巴文"], ["age", 1], ["city", "北京"]]

遍历对象

const person = {
    name: "东巴文",
    age: 1
};

for (const [key, value] of Object.entries(person)) {
    console.log(`${key}: ${value}`);
}
// name: 东巴文
// age: 1

转换为Map

const person = {
    name: "东巴文",
    age: 1
};

const map = new Map(Object.entries(person));
console.log(map.get("name"));  // "东巴文"

Object.values

Object.values返回对象的可枚举值数组。

基本用法

const person = {
    name: "东巴文",
    age: 1,
    city: "北京"
};

const values = Object.values(person);
console.log(values);  // ["东巴文", 1, "北京"]

应用场景

const scores = {
    math: 90,
    english: 85,
    science: 95
};

// 计算总分
const total = Object.values(scores).reduce((a, b) => a + b, 0);
console.log(total);  // 270

// 计算平均分
const average = total / Object.values(scores).length;
console.log(average);  // 90

Object.fromEntries

Object.fromEntries将键值对数组转为对象。

基本用法

const entries = [
    ["name", "东巴文"],
    ["age", 1],
    ["city", "北京"]
];

const obj = Object.fromEntries(entries);
console.log(obj);  // { name: "东巴文", age: 1, city: "北京" }

Map转对象

const map = new Map([
    ["name", "东巴文"],
    ["age", 1]
]);

const obj = Object.fromEntries(map);
console.log(obj);  // { name: "东巴文", age: 1 }

过滤对象属性

const person = {
    name: "东巴文",
    age: 1,
    password: "secret",
    token: "abc123"
};

// 过滤敏感属性
const safePerson = Object.fromEntries(
    Object.entries(person).filter(([key]) => 
        !["password", "token"].includes(key)
    )
);

console.log(safePerson);  // { name: "东巴文", age: 1 }

转换对象值

const person = {
    name: "东巴文",
    age: "1",
    score: "90"
};

// 转换数值类型
const converted = Object.fromEntries(
    Object.entries(person).map(([key, value]) => [
        key,
        isNaN(value) ? value : Number(value)
    ])
);

console.log(converted);  // { name: "东巴文", age: 1, score: 90 }

Object.keys

Object.keys返回对象的可枚举属性名数组。

基本用法

const person = {
    name: "东巴文",
    age: 1,
    city: "北京"
};

const keys = Object.keys(person);
console.log(keys);  // ["name", "age", "city"]

检查对象是否为空

function isEmpty(obj) {
    return Object.keys(obj).length === 0;
}

isEmpty({});        // true
isEmpty({ a: 1 });  // false

获取属性数量

const person = {
    name: "东巴文",
    age: 1
};

const count = Object.keys(person).length;
console.log(count);  // 2

对象方法对比

方法 返回值 东巴文建议
Object.keys 属性名数组 遍历属性名
Object.values 属性值数组 遍历属性值
Object.entries 键值对数组 遍历键值对
Object.fromEntries 对象 数组转对象

下一步

掌握对象解构与扩展后,让我们继续学习:

  1. 字符串方法 - 学习字符串操作
  2. 正则表达式 - 学习正则表达式
  3. DOM基础 - 学习DOM操作

东巴文(db-w.cn) - 让编程学习更简单

📦 东巴文寄语:对象解构和展开运算符是ES6最重要的特性之一,它们让对象操作变得更加简洁和直观。掌握这些技巧,能大大提高你的开发效率。在 db-w.cn,我们帮你掌握现代JavaScript!