Lodash源码阅读-copyObject

Lodash 源码阅读-copyObject

功能概述

copyObject 是 Lodash 内部的一个工具函数,主要用于将源对象的特定属性复制到目标对象上。它支持自定义复制行为,能处理新对象创建和现有对象更新两种情况,是 Lodash 实现对象操作相关方法的基础函数。

前置学习

依赖函数

  • baseAssignValue:底层的属性赋值实现,不检查现有值,直接赋值
  • assignValue:智能属性赋值,会检查属性是否需要更新
  • Object 构造器 :用于在 isNew 为 true 且未提供 object 时创建空对象

技术知识

  • JavaScript 对象遍历:通过索引和长度进行属性遍历
  • 对象属性赋值:了解 JavaScript 中对象属性的赋值机制
  • 函数回调模式:理解如何使用自定义函数(customizer)来控制复制行为
  • 引用类型和值类型:理解 JavaScript 中的值传递和引用传递

源码实现

javascript 复制代码
function copyObject(source, props, object, customizer) {
  var isNew = !object;
  object || (object = {});

  var index = -1,
    length = props.length;

  while (++index < length) {
    var key = props[index];

    var newValue = customizer
      ? customizer(object[key], source[key], key, object, source)
      : undefined;

    if (newValue === undefined) {
      newValue = source[key];
    }
    if (isNew) {
      baseAssignValue(object, key, newValue);
    } else {
      assignValue(object, key, newValue);
    }
  }
  return object;
}

实现思路

copyObject 的实现思路可以归纳为以下几点:

  1. 确定目标对象:如果没有提供目标对象(object),则创建一个新的空对象
  2. 遍历要复制的属性列表(props
  3. 对于每个属性:
    • 如果提供了自定义处理函数(customizer),则使用它计算新值
    • 如果没有提供自定义处理函数或其返回 undefined,则直接使用源对象的属性值
  4. 根据是新建对象还是更新对象,选择不同的赋值方法:
    • 新建对象:使用 baseAssignValue 直接赋值(更高效)
    • 更新对象:使用 assignValue 智能赋值(避免不必要的更新)
  5. 最后返回复制后的对象

这种实现既灵活又高效,能处理多种对象复制场景。

源码解析

让我们逐行解析 copyObject 函数的实现:

javascript 复制代码
function copyObject(source, props, object, customizer) {

函数定义,接收四个参数:

  • source:源对象,要从中复制属性的对象
  • props:要复制的属性列表(数组形式)
  • object:目标对象,要将属性复制到的对象(可选)
  • customizer:自定义处理函数,用于自定义属性复制行为(可选)
javascript 复制代码
var isNew = !object;
object || (object = {});

这两行代码处理目标对象:

  • isNew 标记是否为新对象:如果未提供 object(值为 null、undefined 或其他假值),则 isNew 为 true
  • 如果未提供 object,则创建一个新的空对象作为目标对象
javascript 复制代码
  var index = -1,
      length = props.length;

  while (++index < length) {

设置循环变量,准备遍历属性列表。

javascript 复制代码
var key = props[index];

获取当前要复制的属性名。

javascript 复制代码
var newValue = customizer
  ? customizer(object[key], source[key], key, object, source)
  : undefined;

这行代码处理自定义复制行为:

  • 如果提供了 customizer 函数,则调用它来计算新值
  • 传递给 customizer 函数的参数依次为:目标对象的当前值、源对象的当前值、属性名、目标对象、源对象
  • 如果没有提供 customizer,则 newValueundefined
javascript 复制代码
if (newValue === undefined) {
  newValue = source[key];
}

这是一个巧妙的设计:如果 customizer 返回 undefined(或者没有提供 customizer),则使用源对象的原始值。这样,自定义函数可以选择性地处理某些属性,而对于返回 undefined 的情况,会回退到默认复制行为。

javascript 复制代码
if (isNew) {
  baseAssignValue(object, key, newValue);
} else {
  assignValue(object, key, newValue);
}

根据目标对象是新建的还是已存在的,选择不同的赋值方法:

  • 如果是新对象(isNew 为 true),使用 baseAssignValue 直接赋值,因为新对象上肯定没有现有属性,不需要做额外检查
  • 如果是现有对象,使用 assignValue 进行智能赋值,会先检查是否需要更新(避免不必要的操作)
javascript 复制代码
  }
  return object;
}

完成所有属性的复制后,返回目标对象。

baseAssignValue 和 assignValue 的选择逻辑

copyObject 在赋值时选择了两个不同的函数,这是一个重要的性能优化:

  1. 对于新对象 :使用 baseAssignValue

    • 新对象上肯定没有现有属性,所以不需要进行 assignValue 中的值比较
    • baseAssignValue 是直接赋值,少了条件判断,性能更高
  2. 对于现有对象 :使用 assignValue

    • 现有对象可能已有同名属性,需要先检查是否值相同
    • 如果值相同则跳过赋值,避免不必要的操作(特别是对于有 getter/setter 的属性)

这种区分处理的方式可以在保持功能完整的同时提高性能。

总结

copyObject 是 Lodash 中一个设计精巧的内部工具函数,它通过以下几个特点实现了高效灵活的对象属性复制:

  1. 灵活性:支持自定义处理函数,可以控制每个属性的复制行为
  2. 效率优化:根据目标对象是新建还是已存在,选择最优的赋值方法
  3. 功能完备:能处理多种属性复制场景,是 Lodash 对象操作方法的基础

这个函数体现了几个重要的设计原则:

  1. 单一职责原则:函数只负责对象属性的复制,不关心属性来源和选择逻辑
  2. 开放/封闭原则:通过 customizer 参数扩展功能,而不需要修改基础代码
  3. 性能优化:在保证功能的前提下,针对不同场景使用最优实现
  4. 合成复用:借助 baseAssignValue 和 assignValue 等基础函数构建更复杂的功能
相关推荐
番茄比较犟10 分钟前
Combine知识点switchToLatest
前端
北京_宏哥11 分钟前
🔥《爆肝整理》保姆级系列教程-玩转Charles抓包神器教程(15)-Charles如何配置反向代理
前端·面试·charles
Process14 分钟前
前端图片技术深度解析:格式选择、渲染原理与性能优化
前端·面试·性能优化
大松鼠君15 分钟前
轿车3D展示
前端·webgl·three.js
却尘15 分钟前
URL参数传递的两种方式:查询参数与路径参数详解
前端
下辈子再也不写代码了17 分钟前
分片下载、断点续传与实时速度显示的实现方法
前端·后端·github
婷婷婷婷18 分钟前
AntV X6 常用方法
前端
LucianaiB27 分钟前
拿到Offer,租房怎么办?看我用高德MCP+腾讯云MCP,帮你分分钟搞定!
前端·后端·cursor
用户175923421502833 分钟前
D3.js - 基本用法
前端·d3.js
Mr.Liu61 小时前
小程序30-wxml语法-声明和绑定数据
前端·微信小程序·小程序