Lodash 源码阅读-baseAssignValue
功能概述
baseAssignValue
是 Lodash 中的一个内部工具函数,用于将值赋给对象的属性,是 assignValue
的基础实现版本。它的特点是直接赋值,不进行任何相等性检查,同时对 __proto__
属性有特殊处理,以防止原型污染攻击。
前置学习
依赖函数
- defineProperty :对象属性定义工具,用于安全地处理
__proto__
属性
技术知识
- 对象属性赋值:JavaScript 中对象属性的赋值机制
- 原型污染攻击 :通过修改
__proto__
属性导致的安全问题 - Object.defineProperty:JavaScript 中定义或修改对象属性的 API
源码实现
javascript
function baseAssignValue(object, key, value) {
if (key == "__proto__" && defineProperty) {
defineProperty(object, key, {
configurable: true,
enumerable: true,
value: value,
writable: true,
});
} else {
object[key] = value;
}
}
实现思路
baseAssignValue
的实现思路非常直接:
-
首先检查要赋值的键名是否为
__proto__
,这是一个特殊的键,需要特殊处理- 如果是
__proto__
且存在defineProperty
方法(即环境支持Object.defineProperty
),则使用defineProperty
安全地设置该属性 - 这么做是为了防止原型链污染攻击,保证操作的安全性
- 如果是
-
如果不是
__proto__
或环境不支持defineProperty
,就直接使用赋值运算符=
设置属性- 这是 JavaScript 中最基本的属性赋值方式
源码解析
让我们逐行分析 baseAssignValue
函数的实现:
javascript
function baseAssignValue(object, key, value) {
函数定义,接收三个参数:
object
:要修改的目标对象key
:要设置的属性名value
:要赋的值
javascript
if (key == '__proto__' && defineProperty) {
第一个条件检查,判断:
- 属性名是否为
__proto__
(注意这里使用的是宽松相等==
,所以会做类型转换) defineProperty
是否可用(在 Lodash 内部,defineProperty
是对Object.defineProperty
的引用或自定义实现)
这个检查很重要,因为 __proto__
是一个特殊属性,直接设置它可能导致原型链污染,产生安全风险。
javascript
defineProperty(object, key, {
configurable: true,
enumerable: true,
value: value,
writable: true,
});
如果条件满足,使用 defineProperty
安全地定义该属性,并设置属性描述符:
configurable: true
:允许属性被删除或重新配置enumerable: true
:允许属性在对象的属性枚举中出现value: value
:设置属性的值为传入的value
writable: true
:允许属性的值被修改
这种方式比直接赋值更安全,特别是对于 __proto__
这样的特殊属性。
javascript
} else {
object[key] = value;
}
如果不是 __proto__
属性或环境不支持 defineProperty
,则直接使用标准的属性赋值语法。这是处理常规属性的快速路径。
原型污染问题
最新版的 Chrome 浏览器中暂时没有用代码验证出来
与 assignValue 的关系
baseAssignValue
是 assignValue
的基础实现。assignValue
在调用 baseAssignValue
前会进行额外的检查:
javascript
function assignValue(object, key, value) {
var objValue = object[key];
if (
!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
(value === undefined && !(key in object))
) {
baseAssignValue(object, key, value);
}
}
assignValue
会:
- 检查对象是否已有同名且值相等的属性(使用
eq
判断) - 检查值是否为
undefined
且对象上不存在该属性
只有当需要更新值时,才会调用 baseAssignValue
进行实际赋值操作。
总结
baseAssignValue
是 Lodash 内部的一个基础工具函数,用于安全地为对象设置属性值。