后端转全栈学习-Day5-JavaScript 基础-3

第5天:JavaScript 对象详解

学习时间:约 1 小时

前置知识:第3天的变量、类型,第4天的函数


目录

  1. 对象是什么
  2. 创建对象
  3. 访问属性
  4. 增删改属性
  5. 计算属性名
  6. 对象遍历
  7. 对象解构
  8. 展开运算符(对象展开)
  9. 嵌套对象与可选链
  10. [Object 常用静态方法](#Object 常用静态方法)
  11. 对象是引用类型
  12. 常用模式:对象与数组互转
  13. 练习
  14. 常见陷阱

1. 对象是什么

1.1 最简单的理解

对象 = 一组键值对的集合。

每个键(也叫属性名)对应一个值,就像一个字典:

js 复制代码
// 一个"用户"对象
const user = {
  name: '小明',       // 键是 name,值是 '小明'
  age: 25,            // 键是 age,值是 25
  email: 'xm@example.com'
}

你可以把对象想象成一张表格:

name '小明'
age 25
email 'xm@example.com'

1.2 对象和其他语言的对比

java 复制代码
// Java:必须先定义类,再创建对象
public class User {
    private String name;
    private int age;
    private String email;
    // 还要写构造函数、getter、setter...
}
User user = new User("小明", 25, "xm@example.com");
js 复制代码
// JS:直接创建对象,不需要类
const user = {
  name: '小明',
  age: 25,
  email: 'xm@example.com'
}
Java JavaScript
必须先定义类 直接创建对象,不需要类
属性类型固定 属性值可以是任意类型
属性在编译时确定 属性可以随时增删
. 访问属性 .[] 访问属性

1.3 对象可以包含什么

对象的值可以是任何类型------数字、字符串、布尔、数组、函数,甚至另一个对象:

js 复制代码
const product = {
  name: 'iPhone 15',          // 字符串
  price: 7999,                // 数字
  inStock: true,              // 布尔
  tags: ['手机', '苹果'],     // 数组
  specs: {                    // 另一个对象
    weight: '171g',
    color: '黑色'
  },
  getInfo() {                 // 函数(方法)
    return `${this.name} - ¥${this.price}`
  }
}

2. 创建对象

2.1 对象字面量(最常用)

{} 直接定义:

js 复制代码
// 空对象
const obj = {}

// 带属性的对象
const user = {
  name: '小明',
  age: 25
}

2.2 new Object()

js 复制代码
const user = new Object()
user.name = '小明'
user.age = 25

几乎不用这种写法------字面量更简洁、更直观。

2.3 什么时候用哪种?

方式 推荐度 场景
字面量 {} ⭐⭐⭐ 99% 的场景
new Object() 几乎不用

3. 访问属性

3.1 点语法(最常用)

js 复制代码
const user = {
  name: '小明',
  age: 25
}

console.log(user.name)    // '小明'
console.log(user.age)     // 25

3.2 方括号语法

js 复制代码
const user = {
  name: '小明',
  age: 25
}

console.log(user['name'])    // '小明'
console.log(user['age'])     // 25

什么时候用方括号?

当属性名是变量、包含特殊字符、或者动态拼接时:

js 复制代码
const user = {
  name: '小明',
  'user-age': 25          // 属性名包含连字符
}

// ❌ 点语法访问不了连字符属性名
console.log(user.user-age)    // NaN(JS 理解为 user.user 减 age)

// ✅ 方括号可以
console.log(user['user-age']) // 25

// 动态属性名
const key = 'name'
console.log(user[key])    // '小明'(key 是变量,值是 'name')

3.3 访问不存在的属性

js 复制代码
const user = {
  name: '小明',
  age: 25
}

console.log(user.email)     // undefined(不报错,返回 undefined)
console.log(user.address)   // undefined

和 Java 的区别

java 复制代码
// Java:访问不存在的字段会编译错误
user.email    // 编译错误:User 类没有 email 字段
js 复制代码
// JS:访问不存在的属性返回 undefined
user.email    // undefined(运行时不报错)

3.4 检查属性是否存在

js 复制代码
const user = {
  name: '小明',
  age: 25
}

// 方式 1:in 操作符
console.log('name' in user)     // true
console.log('email' in user)    // false

// 方式 2:!== undefined
console.log(user.name !== undefined)    // true
console.log(user.email !== undefined)   // false

// 方式 3:hasOwnProperty
console.log(user.hasOwnProperty('name'))    // true
console.log(user.hasOwnProperty('email'))   // false

4. 增删改属性

4.1 添加属性

js 复制代码
const user = {
  name: '小明'
}

// 直接赋值即可添加
user.age = 25
user.email = 'xm@example.com'

console.log(user)
// { name: '小明', age: 25, email: 'xm@example.com' }

4.2 修改属性

js 复制代码
const user = {
  name: '小明',
  age: 25
}

// 直接赋值即可修改
user.age = 26
user.name = '大明'

console.log(user)
// { name: '大明', age: 26 }

4.3 删除属性

js 复制代码
const user = {
  name: '小明',
  age: 25,
  email: 'xm@example.com'
}

// 用 delete 关键字删除属性
delete user.email

console.log(user)
// { name: '小明', age: 25 }(email 被删除了)

4.4 动态属性名(变量作为属性名)

js 复制代码
const user = {}
const fieldName = 'age'
const fieldValue = 25

// 用方括号语法动态设置属性
user[fieldName] = fieldValue

console.log(user)    // { age: 25 }

// 等同于
user['age'] = 25

5. 计算属性名

5.1 ES6 计算属性名

ES6 允许用表达式作为属性名,用 [] 包起来:

js 复制代码
const prefix = 'user'

// 属性名用表达式计算
const data = {
  [prefix + 'Name']: '小明',
  [prefix + 'Age']: 25,
  [`${prefix}Email`]: 'xm@example.com'
}

console.log(data)
// { userName: '小明', userAge: 25, userEmail: 'xm@example.com' }

5.2 实际场景

js 复制代码
// 根据条件设置不同的属性名
const field = 'status'
const value = 'active'

const update = {
  [field]: value,
  [`${field}UpdatedAt`]: new Date().toISOString()
}

console.log(update)
// { status: 'active', statusUpdatedAt: '2026-06-04T...' }

6. 对象遍历

6.1 for...in 循环

遍历对象的所有可枚举属性(包括继承的):

js 复制代码
const user = {
  name: '小明',
  age: 25,
  email: 'xm@example.com'
}

for (const key in user) {
  console.log(`${key}: ${user[key]}`)
}
// name: 小明
// age: 25
// email: xm@example.com

注意:for...in 会遍历原型链上的属性 ,所以遍历对象时一般用 Object.keys() 更安全。

6.2 Object.keys() --- 获取所有键

js 复制代码
const user = {
  name: '小明',
  age: 25,
  email: 'xm@example.com'
}

const keys = Object.keys(user)
console.log(keys)    // ['name', 'age', 'email']

6.3 Object.values() --- 获取所有值

js 复制代码
const user = {
  name: '小明',
  age: 25,
  email: 'xm@example.com'
}

const values = Object.values(user)
console.log(values)    // ['小明', 25, 'xm@example.com']

6.4 Object.entries() --- 获取所有键值对

把对象变成二维数组,每个元素是 [key, value]

js 复制代码
const user = {
  name: '小明',
  age: 25,
  email: 'xm@example.com'
}

const entries = Object.entries(user)
console.log(entries)
// [ ['name', '小明'], ['age', 25], ['email', 'xm@example.com'] ]

配合解构遍历

js 复制代码
for (const [key, value] of Object.entries(user)) {
  console.log(`${key}: ${value}`)
}
// name: 小明
// age: 25
// email: xm@example.com

6.5 三种方法的对比

方法 返回值 用途
Object.keys(obj) ['name', 'age'] 只需要键
Object.values(obj) ['小明', 25] 只需要值
Object.entries(obj) [['name','小明'], ['age',25]] 键值对都要

7. 对象解构

7.1 基础解构

从对象中提取属性,赋值给同名变量:

js 复制代码
const user = {
  name: '小明',
  age: 25,
  email: 'xm@example.com'
}

// 普通写法
const name = user.name
const age = user.age
const email = user.email

// ✅ 解构写法(一行搞定)
const { name, age, email } = user

console.log(name)    // '小明'
console.log(age)     // 25
console.log(email)   // 'xm@example.com'

7.2 重命名变量

如果不想用属性名作为变量名:

js 复制代码
const user = {
  name: '小明',
  age: 25
}

// 把 name 重命名为 userName
const { name: userName, age: userAge } = user

console.log(userName)    // '小明'
console.log(userAge)     // 25

// ❌ name 变量不存在了
console.log(name)        // ReferenceError: name is not defined

7.3 默认值

属性不存在时使用默认值:

js 复制代码
const user = {
  name: '小明',
  age: 25
}

// email 不存在,使用默认值
const { name, age, email = '未填写' } = user

console.log(name)     // '小明'
console.log(age)      // 25
console.log(email)    // '未填写'(user 没有 email,用了默认值)

7.4 解构 + 重命名 + 默认值组合

js 复制代码
const user = {
  name: '小明',
  age: 25
}

// 提取 name,重命名为 userName,默认值 '匿名'
// 提取 email,重命名为 userEmail,默认值 '无'
const { name: userName = '匿名', email: userEmail = '无' } = user

console.log(userName)    // '小明'(有值,不用默认)
console.log(userEmail)   // '无'(没有值,用默认)

7.5 嵌套解构

从嵌套对象中提取属性:

js 复制代码
const response = {
  code: 200,
  data: {
    user: {
      name: '小明',
      address: {
        city: '北京',
        street: '朝阳路'
      }
    }
  }
}

// 一层层解构
const { data: { user: { name, address: { city } } } } = response

console.log(name)    // '小明'
console.log(city)    // '北京'

7.6 函数参数解构

Day 4 已经讲过,这里再回顾一下:

js 复制代码
// 普通写法
function greet(user) {
  console.log(`你好,${user.name}!你${user.age}岁了。`)
}

// ✅ 解构写法
function greet({ name, age }) {
  console.log(`你好,${name}!你${age}岁了。`)
}

greet({ name: '小明', age: 25 })    // 你好,小明!你25岁了。

8. 展开运算符(对象展开)

8.1 浅拷贝对象

js 复制代码
const original = {
  name: '小明',
  age: 25
}

// 用 ... 创建一个新对象(浅拷贝)
const copy = { ...original }

console.log(copy)          // { name: '小明', age: 25 }
console.log(copy === original)   // false(是不同的对象)

8.2 合并对象

js 复制代码
const defaults = {
  theme: 'light',
  fontSize: 14,
  language: 'zh'
}

const userSettings = {
  theme: 'dark',
  fontSize: 16
}

// 合并:后面的覆盖前面的
const settings = { ...defaults, ...userSettings }

console.log(settings)
// { theme: 'dark', fontSize: 16, language: 'zh' }
// userSettings 的 theme 覆盖了 defaults 的 theme
// userSettings 没有 language,所以保留 defaults 的

8.3 添加/覆盖属性

js 复制代码
const user = {
  name: '小明',
  age: 25
}

// 添加新属性
const updated = { ...user, email: 'xm@example.com' }
console.log(updated)
// { name: '小明', age: 25, email: 'xm@example.com' }

// 覆盖已有属性
const older = { ...user, age: 26 }
console.log(older)
// { name: '小明', age: 26 }

8.4 展开的顺序很重要

js 复制代码
const base = { a: 1, b: 2, c: 3 }

// 后面的覆盖前面的
const result = { ...base, b: 99 }
console.log(result)    // { a: 1, b: 99, c: 3 }

// 前面的不会覆盖后面的
const result2 = { b: 99, ...base }
console.log(result2)   // { a: 1, b: 2, c: 3 }

9. 嵌套对象与可选链

9.1 嵌套对象

对象的属性值可以是另一个对象:

js 复制代码
const order = {
  id: 1001,
  customer: {
    name: '小明',
    address: {
      city: '北京',
      street: '朝阳路 123 号'
    }
  },
  items: [
    { name: 'iPhone', price: 7999 },
    { name: 'AirPods', price: 1999 }
  ]
}

// 访问嵌套属性
console.log(order.customer.name)             // '小明'
console.log(order.customer.address.city)     // '北京'
console.log(order.items[0].name)             // 'iPhone'

9.2 可选链操作符 ?.(ES2020)

当不确定嵌套的某一层是否存在时,用 ?. 安全访问:

js 复制代码
const user = {
  name: '小明'
  // 没有 address 属性
}

// ❌ 普通访问会报错
// console.log(user.address.city)   // TypeError: Cannot read property 'city' of undefined

// ✅ 可选链:如果 address 是 null 或 undefined,直接返回 undefined
console.log(user.address?.city)    // undefined(不报错)

// 也可以用在方法调用
console.log(user.getName?.())      // undefined(方法不存在,不报错)

// 也可以用在数组
console.log(user.hobbies?.[0])     // undefined(属性不存在,不报错)

9.3 可选链的链式使用

js 复制代码
const response = {
  code: 200,
  data: {
    user: {
      name: '小明'
      // 没有 address
    }
  }
}

// 安全地访问深层属性
const city = response.data?.user?.address?.city
console.log(city)    // undefined(不报错)

// 配合空值合并运算符 ?? 提供默认值
const cityOrDefault = response.data?.user?.address?.city ?? '未知城市'
console.log(cityOrDefault)    // '未知城市'

9.4 ?. 和 && 的对比

js 复制代码
const user = { name: '小明' }

// 以前的写法(用 && 短路)
const city1 = user.address && user.address.city

// ✅ 现在的写法(可选链)
const city2 = user.address?.city

// 两者效果一样,但 ?. 更简洁、更易读

10. Object 常用静态方法

10.1 Object.keys() / values() / entries()

前面已经讲过,这里做个小总结:

js 复制代码
const user = { name: '小明', age: 25, city: '北京' }

Object.keys(user)      // ['name', 'age', 'city']
Object.values(user)    // ['小明', 25, '北京']
Object.entries(user)   // [['name','小明'], ['age',25], ['city','北京']]

10.2 Object.assign() --- 合并对象

js 复制代码
const target = { a: 1, b: 2 }
const source = { b: 3, c: 4 }

// 把 source 的属性合并到 target(会修改 target)
Object.assign(target, source)

console.log(target)    // { a: 1, b: 3, c: 4 }
console.log(source)    // { b: 3, c: 4 }(source 不变)

实际场景:给对象添加默认值

js 复制代码
const user = { name: '小明' }

// 给 user 添加默认属性(user 已有的不会被覆盖)
Object.assign(user, { age: 0, role: '用户', email: '' })

console.log(user)
// { name: '小明', age: 0, role: '用户', email: '' }

10.3 Object.freeze() --- 冻结对象

冻结后,对象的属性不能被修改、添加、删除:

js 复制代码
const config = {
  apiUrl: 'https://api.example.com',
  timeout: 3000
}

Object.freeze(config)

// ❌ 修改无效(严格模式下会报错)
config.apiUrl = 'https://hack.com'
console.log(config.apiUrl)    // 'https://api.example.com'(没变)

// ❌ 添加无效
config.newProp = 'hello'
console.log(config.newProp)   // undefined(没加上)

// ❌ 删除无效
delete config.timeout
console.log(config.timeout)   // 3000(没删掉)

10.4 Object.is() --- 严格比较

js 复制代码
// === 和 Object.is() 大部分情况一样
console.log(1 === 1)              // true
console.log(Object.is(1, 1))      // true

// 但有两个特例
console.log(+0 === -0)            // true
console.log(Object.is(+0, -0))    // false

console.log(NaN === NaN)          // false
console.log(Object.is(NaN, NaN))  // true

10.5 方法速查表

方法 作用 示例
Object.keys(obj) 获取所有键 ['name', 'age']
Object.values(obj) 获取所有值 ['小明', 25]
Object.entries(obj) 获取所有键值对 [['name','小明']]
Object.assign(target, source) 合并对象(修改 target) { a:1, b:3 }
Object.freeze(obj) 冻结对象(不可修改) 冻结后的对象
Object.is(a, b) 严格相等比较 true / false

11. 对象是引用类型

11.1 值类型 vs 引用类型

js 复制代码
// 值类型(基本类型):赋值时复制值
let a = 10
let b = a      // b 是 a 的副本
b = 20
console.log(a)   // 10(a 不受影响)

// 引用类型(对象):赋值时复制引用(指针)
let obj1 = { name: '小明' }
let obj2 = obj1  // obj2 和 obj1 指向同一个对象
obj2.name = '大明'
console.log(obj1.name)   // '大明'(obj1 也被改了!)

和 Java 的对比

java 复制代码
// Java:对象变量也是引用
User user1 = new User("小明");
User user2 = user1;        // user2 和 user1 指向同一个对象
user2.setName("大明");
System.out.println(user1.getName());   // "大明"(一样)

11.2 为什么 obj2 改了 obj1 也变了?

因为 obj2 = obj1 不是复制对象,而是复制了对象的"地址"。两个变量指向同一块内存:

复制代码
obj1 ──→ ┌──────────────┐
         │ name: '小明'  │
obj2 ──→ └──────────────┘

// 改 obj2.name 就是改了这块内存里的 name
// obj1 读的也是这块内存,所以也变了

11.3 浅拷贝 vs 深拷贝

浅拷贝:只复制第一层,嵌套的还是共享引用:

js 复制代码
const original = {
  name: '小明',
  address: {
    city: '北京'
  }
}

// 浅拷贝(用展开运算符)
const copy = { ...original }

copy.name = '大明'
console.log(original.name)    // '小明'(第一层不受影响)

copy.address.city = '上海'
console.log(original.address.city)   // '上海'(嵌套对象被影响了!)

深拷贝:完全复制,互不影响:

js 复制代码
const original = {
  name: '小明',
  address: {
    city: '北京'
  }
}

// 深拷贝(用 JSON,最简单的方式)
const deepCopy = JSON.parse(JSON.stringify(original))

deepCopy.address.city = '上海'
console.log(original.address.city)   // '北京'(不受影响)

JSON 深拷贝的限制

  • 不能复制函数(会被丢弃)
  • 不能复制 undefined(会被丢弃)
  • 不能复制 Date(会变成字符串)
  • 不能处理循环引用

更可靠的方式(ES2024):

js 复制代码
// structuredClone --- 浏览器原生深拷贝
const deepCopy = structuredClone(original)

12. 常用模式:对象与数组互转

12.1 对象转数组

js 复制代码
const user = { name: '小明', age: 25, city: '北京' }

// 转成键数组
const keys = Object.keys(user)          // ['name', 'age', 'city']

// 转成值数组
const values = Object.values(user)      // ['小明', 25, '北京']

// 转成键值对数组
const entries = Object.entries(user)    // [['name','小明'], ['age',25], ['city','北京']]

12.2 数组转对象

js 复制代码
// 用 Object.fromEntries 把键值对数组转成对象
const entries = [['name', '小明'], ['age', 25], ['city', '北京']]
const obj = Object.fromEntries(entries)
console.log(obj)    // { name: '小明', age: 25, city: '北京' }

12.3 实际场景:对象属性映射

js 复制代码
const user = { name: '小明', age: 25, city: '北京' }

// 把所有值变成大写
const upper = Object.fromEntries(
  Object.entries(user).map(([key, value]) => [key, String(value).toUpperCase()])
)
console.log(upper)    // { name: '小明', age: '25', city: '北京' }

// 过滤掉值为空的属性
const cleaned = Object.fromEntries(
  Object.entries(user).filter(([key, value]) => value !== '' && value !== null)
)

13. 练习

练习 1(初级):创建和访问对象

js 复制代码
// 创建一个商品对象,包含 name、price、stock 三个属性
// 然后用两种方式(点语法、方括号)分别访问每个属性
const product = {
  // 你的代码
}

console.log(product.name)       // 点语法
console.log(product['price'])   // 方括号语法

练习 2(初级):对象解构

js 复制代码
const response = {
  code: 200,
  message: 'success',
  data: {
    id: 1,
    name: 'iPhone 15',
    price: 7999,
    tags: ['手机', '苹果']
  }
}

// 用解构提取 id、name、price
// 然后用模板字符串输出:"商品 iPhone 15 (ID: 1) 售价 ¥7999"
// 你的代码

练习 3(中级):对象遍历 + 数组方法

js 复制代码
const products = {
  'p001': { name: 'iPhone', price: 7999, stock: 10 },
  'p002': { name: 'iPad', price: 3499, stock: 0 },
  'p003': { name: 'AirPods', price: 1999, stock: 50 },
  'p004': { name: 'MacBook', price: 12999, stock: 5 }
}

// 1. 用 Object.values() + filter 找出有库存的商品
// 2. 用 Object.entries() + map 生成 "商品名: ¥价格" 格式的数组
// 3. 用 Object.values() + reduce 计算所有商品的总库存

练习 4(中级):展开运算符 + 合并

js 复制代码
const defaultConfig = {
  theme: 'light',
  fontSize: 14,
  showSidebar: true,
  language: 'zh-CN'
}

const userConfig = {
  theme: 'dark',
  fontSize: 16
}

// 1. 用展开运算符合并两个配置(用户配置覆盖默认配置)
// 2. 在合并结果中添加一个新属性 version: '1.0'
// 你的代码

练习 5(综合):商品数据处理

js 复制代码
const shop = {
  name: '数码商城',
  products: {
    'p001': { name: 'iPhone 15', price: 7999, category: '手机' },
    'p002': { name: 'iPad Pro', price: 6799, category: '平板' },
    'p003': { name: 'AirPods Pro', price: 1999, category: '配件' },
    'p004': { name: 'MacBook Pro', price: 14999, category: '电脑' },
    'p005': { name: 'Apple Watch', price: 2999, category: '配件' }
  }
}

// 1. 获取所有商品的名字列表(用 Object.values + map)
// 2. 找出所有价格超过 5000 的商品(用 Object.entries + filter)
// 3. 按 category 分组,生成 { 手机: [...], 平板: [...], 配件: [...], 电脑: [...] }
// 4. 计算所有商品的平均价格

14. 常见陷阱

陷阱 1:忘记对象是引用类型

js 复制代码
const user = { name: '小明', age: 25 }

// ❌ 以为 copy 是独立的副本
const copy = user
copy.age = 26
console.log(user.age)    // 26(user 也被改了!)

// ✅ 用展开运算符创建新对象
const copy2 = { ...user }
copy2.age = 27
console.log(user.age)    // 26(user 不受影响)

陷阱 2:for...in 遍历原型链

js 复制代码
// 给所有对象添加一个方法(不推荐,只是演示)
Object.prototype.greet = function() { console.log('hello') }

const user = { name: '小明', age: 25 }

// ❌ for...in 会遍历到 greet
for (const key in user) {
  console.log(key)
}
// 输出:name, age, greet(greet 是继承来的)

// ✅ 用 Object.keys() 只遍历自己的属性
Object.keys(user).forEach(key => {
  console.log(key)
})
// 输出:name, age

陷阱 3:解构时变量名不匹配

js 复制代码
const user = { name: '小明', age: 25 }

// ❌ 变量名和属性名不匹配
const { username, userage } = user
console.log(username)    // undefined(user 没有 username 属性)
console.log(userage)     // undefined

// ✅ 用重命名
const { name: username, age: userage } = user
console.log(username)    // '小明'
console.log(userage)     // 25

陷阱 4:可选链和空值混用

js 复制代码
const user = { name: '小明', age: 0 }

// ❌ age 是 0,但 0 是 falsy,|| 会跳过
const age1 = user.age || 18
console.log(age1)    // 18(0 被当成 falsy 了)

// ✅ 用 ??(空值合并运算符),只在 null/undefined 时才用默认值
const age2 = user.age ?? 18
console.log(age2)    // 0(0 不是 null/undefined,保留原值)

陷阱 5:展开运算符只做浅拷贝

js 复制代码
const original = {
  name: '小明',
  scores: [90, 85, 92]
}

const copy = { ...original }

// 第一层是独立的
copy.name = '大明'
console.log(original.name)    // '小明'(不受影响)

// 但数组是引用类型,还是共享的
copy.scores.push(100)
console.log(original.scores)  // [90, 85, 92, 100](被影响了!)

// ✅ 要深拷贝嵌套的数组/对象,需要单独处理
const deepCopy = {
  ...original,
  scores: [...original.scores]   // 数组也展开
}

附:今日速查

js 复制代码
// 创建对象
const obj = { name: '小明', age: 25 }

// 访问属性
obj.name              // 点语法
obj['name']           // 方括号语法(支持变量和特殊字符)

// 增删改
obj.email = '...'     // 添加/修改
delete obj.email      // 删除
'name' in obj         // 检查属性是否存在

// 遍历
Object.keys(obj)      // ['name', 'age']
Object.values(obj)    // ['小明', 25]
Object.entries(obj)   // [['name','小明'], ['age',25]]

// 解构
const { name, age } = obj                        // 基础解构
const { name: userName } = obj                    // 重命名
const { email = '无' } = obj                      // 默认值
const { a: { b } } = nested                       // 嵌套解构

// 展开运算符
const copy = { ...obj }                           // 浅拷贝
const merged = { ...defaults, ...userSettings }   // 合并

// 可选链
user?.address?.city                               // 安全访问嵌套属性
user?.getName?.()                                 // 安全调用方法

// 对象 ↔ 数组
Object.keys/values/entries(obj)                   // 对象 → 数组
Object.fromEntries(entries)                       // 数组 → 对象

// 深拷贝
JSON.parse(JSON.stringify(obj))                   // JSON 深拷贝
structuredClone(obj)                              // 原生深拷贝(ES2024)

// 冻结
Object.freeze(obj)                                // 不可修改
相关推荐
ssshooter1 小时前
为什么父元素的高度不会包含子元素的 margin?
前端·javascript·面试
oqX0Cazj21 小时前
2026超火Go-Zero实战:从架构原理到高并发接口落地,彻底解决接口超时、雪崩问题
开发语言·架构·golang
Goodbye1 小时前
JavaScript 同步与异步编程深度解析
javascript
Amo Xiang1 小时前
JS 逆向系统进阶路线:专栏总纲与文章导航
javascript·js逆向·前端加密·爬虫逆向·反爬虫
学会去珍惜1 小时前
C语言简介
c语言·开发语言
思麟呀1 小时前
C++11 核心特性(三):强类型枚举、static_assert 与 std::tuple
开发语言·c++
hoiii1872 小时前
Qt 实现屏幕截图功能
开发语言·qt·命令模式
05大叔2 小时前
对话系统学习,问答型数据库,闲聊型对话数据库
学习
nashane2 小时前
HarmonyOS 6商城开发学习:抢票倒计时与系统日历提醒——票务类场景的完整落地思路
学习·华为·harmonyos