前端开发中的常用工具函数(八)

二十、Object.assign() 方法:

1. 基本语法

Object.assign 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

javascript 复制代码
Object.assign(target, ...sources)
  • target(目标对象):必需。接收属性的对象。
  • sources(源对象):可选。一个或多个源对象,它们的属性将被复制到目标对象。

核心规则:

  1. 如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。
  2. 后面的源对象的属性将类似地覆盖前面的源对象的属性。

2. 基础示例

(1) 基本合并

javascript 复制代码
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);        // 输出: { a: 1, b: 4, c: 5 }
console.log(returnedTarget === target); // 输出: true (返回的是同一个对象引用)

(2) 合并多个对象

javascript 复制代码
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const obj3 = { c: 3 };

const merged = Object.assign({}, obj1, obj2, obj3);
console.log(merged); // 输出: { a: 1, b: 2, c: 3 }

小技巧 :如果不希望修改原对象,通常将 target 设为一个空对象 {}

示例:

3. 企业开发中的实际应用场景

场景一:组件默认配置与用户自定义配置合并

这是 Object.assign 最经典的用法。开发通用组件(如弹窗、表格)时,通常有一份默认配置,用户传入的配置需要覆盖默认值。

javascript 复制代码
// 默认配置
const defaultOptions = {
    width: 100,
    height: 50,
    color: 'blue',
    draggable: false
};

// 用户传入的自定义配置
const userOptions = {
    width: 200,
    color: 'red'
};

// 合并策略:创建一个新对象,先放入默认值,再覆盖用户值
const finalOptions = Object.assign({}, defaultOptions, userOptions);

console.log(finalOptions);
// 输出: { width: 200, height: 50, color: 'red', draggable: false }

场景二:Redux/State 状态更新(不可变数据)

在 Redux 或 React 的 Class 组件时代,我们不能直接修改 state,而是需要返回一个新的对象。Object.assign 是实现浅拷贝更新的标准写法。

javascript 复制代码
const initialState = {
    loading: false,
    data: [],
    error: null
};

// 模拟 Reducer 中的状态更新
function reducer(state = initialState, action) {
    switch (action.type) {
        case 'FETCH_START':
            // 返回一个新对象,保持原 state 不变
            return Object.assign({}, state, {
                loading: true
            });
        case 'FETCH_SUCCESS':
            return Object.assign({}, state, {
                loading: false,
                data: action.payload
            });
        default:
            return state;
    }
}

场景三:为对象动态添加属性与方法

虽然可以直接 obj.key = value,但在批量添加或需要保持代码整洁时,Object.assign 很有用。

javascript 复制代码
class User {
    constructor(name) {
        this.name = name;
    }
}

// 动态混入功能(类似于 Mixin 模式)
const features = {
    sayHello() {
        console.log(`Hello, I'm ${this.name}`);
    },
    walk() {
        console.log(`${this.name} is walking`);
    }
};

const user = new User('Jack');
Object.assign(user, features);

user.sayHello(); // 输出: Hello, I'm Jack

4. 注意事项

(1) 浅拷贝------ 最大的坑

这是新手最容易犯的错误。Object.assign 只能拷贝第一层属性。如果源对象的属性值是一个对象(引用类型),拷贝的是该对象的引用。

javascript 复制代码
const source = {
    a: 1,
    b: { 
        c: 2 
    }
};

const target = Object.assign({}, source);

// 修改 target 中嵌套对象的值
target.b.c = 100;

// 悲剧发生了:源对象也被修改了!
console.log(source.b.c); // 输出: 100

避坑指南 :对于深层对象结构,推荐使用 JSON.parse(JSON.stringify(obj)) 进行深拷贝(注意函数和 undefined 会丢失),或使用 Lodash 的 _.cloneDeep

(2) 同名属性的完全覆盖

不仅是值会被覆盖,属性描述符也会被覆盖。

javascript 复制代码
const source = Object.defineProperty({}, 'name', {
    value: 'Source',
    writable: false // 不可写
});

const target = { name: 'Target' };

Object.assign(target, source);

// assign 只拷贝值,不拷贝属性描述符
// target.name 变成了 'Source',但 writable 特性并未复制过来,而是恢复默认
console.log(target.name); // 'Source'

(3) 数组的处理

如果参数是数组,Object.assign 会把数组视为对象处理,键名是索引。

javascript 复制代码
const arr1 = [1, 2, 3];
const arr2 = [4, 5];
const result = Object.assign(arr1, arr2);

console.log(result); // 输出: [4, 5, 3] (不是合并数组,而是属性覆盖)
// 解释: arr2 的 '0':4 覆盖了 arr1 的 '0':1, '1':5 覆盖了 '2':2,'3'未受影响

避坑指南 :合并数组请使用 [...arr1, ...arr2]arr1.concat(arr2)

相关推荐
Hilaku1 小时前
Vue 和 React 真正的差距,不在语法,而在团队犯错成本
前端·javascript·程序员
凤凰院凶涛QAQ1 小时前
《Java版数据结构 & 集合类剖析》栈与队列:“push/pop 是栈的灵魂,offer/poll 是队列的骨架——四组 API,两种人生”
java·开发语言·数据结构
研☆香1 小时前
为什么变量声明在赋值前也能使用?—— 深入理解 JavaScript 变量提升与作用域
开发语言·前端·javascript
右耳朵猫AI1 小时前
PHP周刊2026W28 | 安全更新、Laravel 13.18、Twig 3.28
开发语言·php·laravel
second602 小时前
第一部分:快速上手 —— 建立 C++ 基本语法与编程范式
开发语言·c++
Liora_Yvonne2 小时前
目录结构到底怎么设计?别再把 components 和 utils 当垃圾桶了
前端
郝学胜-神的一滴2 小时前
算法实战:最小k个数——大顶堆的优雅解法
开发语言·数据结构·c++·python·程序人生·算法·排序算法
bksczm2 小时前
linux之线程概念和控制
linux·开发语言·c++
柯克七七2 小时前
我把 bug 修得太干净了,测试组以为这个模块本来就没问题
前端·javascript·typescript