Lodash 源码阅读-baseAssign
功能概述
baseAssign
是 Lodash 内部的一个工具函数,主要用于将源对象的所有自身可枚举属性(不包括继承的属性)复制到目标对象上。它是实现 _.assign
等方法的基础,特点是只复制源对象上的自有属性,不复制原型链上的属性。
前置学习
依赖函数
- copyObject:负责将属性从源对象复制到目标对象的工具函数
- keys:获取对象的所有自身可枚举属性名的函数(不包括继承属性)
技术知识
- JavaScript 对象属性:理解对象自身属性与继承属性的区别
- 可枚举属性:了解 JavaScript 中属性的可枚举性概念
- 对象复制:浅拷贝和属性赋值的基本知识
源码实现
javascript
function baseAssign(object, source) {
return object && copyObject(source, keys(source), object);
}
实现思路
baseAssign
的实现思路非常简洁明了:
- 首先检查目标对象(
object
)是否存在(不是 null 或 undefined) - 如果目标对象存在,则:
- 使用
keys
获取源对象的所有自身可枚举属性名(不包括继承的属性) - 通过
copyObject
将这些属性从源对象复制到目标对象
- 使用
- 最后返回处理后的目标对象
这个函数的关键特点是它使用了 keys
而不是 keysIn
,这使得它只复制源对象的自有属性,而不复制原型链上的属性。
源码解析
让我们逐步分析 baseAssign
函数的实现:
javascript
function baseAssign(object, source) {
函数定义,接收两个参数:
object
:目标对象,要将属性复制到的对象source
:源对象,要从中复制属性的对象
javascript
return object && copyObject(source, keys(source), object);
}
这一行代码包含了函数的全部逻辑,可以分解为两个部分:
-
object &&
:这是一个短路逻辑与操作,确保目标对象存在(不是 null 或 undefined)。如果object
是 falsy 值,函数会直接返回该值(一般是 undefined、null 等),不进行后续操作。 -
copyObject(source, keys(source), object)
:这是函数的核心逻辑,分解来看:keys(source)
:获取源对象的所有自身可枚举属性名(不包括继承的属性)。keys
函数等同于Object.keys
,只返回对象自身的可枚举属性。copyObject(source, keys(source), object)
:调用copyObject
函数,将source
对象中由keys(source)
返回的所有自身属性复制到object
对象上。
整个函数同样巧妙地利用了短路评估和函数组合,用极简的代码实现了完整的功能。
baseAssign 与 baseAssignIn 的区别
baseAssign
和 baseAssignIn
是两个相似但有重要区别的函数:
-
baseAssign:
javascriptfunction baseAssign(object, source) { return object && copyObject(source, keys(source), object); }
使用
keys(source)
只获取源对象自身的可枚举属性。 -
baseAssignIn:
javascriptfunction baseAssignIn(object, source) { return object && copyObject(source, keysIn(source), object); }
使用
keysIn(source)
获取源对象自身和继承的所有可枚举属性。
这个区别决定了这两个函数处理原型链上属性的不同行为,也是它们各自对应的公开 API(_.assign
和 _.assignIn
)功能差异的根本原因。
总结
baseAssign
是 Lodash 中一个设计精巧的内部工具函数,它通过结合 copyObject
和 keys
函数,高效地实现了对象自有属性的复制,排除了继承的属性。设计体现了以下编程原则:
- 单一职责原则:函数只负责一件事情,即复制对象自身的可枚举属性
- 组合优于继承 :通过组合使用
copyObject
和keys
实现功能,展示了函数组合的强大 - 防御性编程:通过短路逻辑检查参数有效性,增强代码健壮性
理解 baseAssign
的实现有助于我们更好地掌握 JavaScript 中对象属性复制的处理方法,尤其是在只需要处理对象自有属性的场景中。它也展示了如何通过选择合适的依赖函数(这里是 keys
vs keysIn
)来实现不同的功能行为。