如何合并含Symbol的JavaScript对象?Lodash merge失效求替代方案
解决Lodash Merge无法处理Symbol类型键的问题
这个坑我之前踩过!Lodash的merge方法确实会忽略Symbol类型的对象键,因为它默认只遍历字符串键,这就导致你用Sequelize的Op(本质是Symbol)作为键的属性被丢失,最终变成空对象。下面给你几个可行的解决办法:
方法1:自定义支持Symbol键的合并函数
自己写一个递归合并函数,手动处理所有字符串键和Symbol键:
function mergeWithSymbols(target, source) { // 遍历源对象的所有键(字符串+Symbol) const allKeys = [...Object.keys(source), ...Object.getOwnPropertySymbols(source)]; for (const key of allKeys) { const targetVal = target[key]; const sourceVal = source[key]; // 递归合并嵌套对象,否则直接覆盖 if (typeof targetVal === 'object' && targetVal !== null && typeof sourceVal === 'object' && sourceVal !== null) { mergeWithSymbols(targetVal, sourceVal); } else { target[key] = sourceVal; } } return target; } // 使用示例 const selectA = { where: { text: "something" } }; const selectB = { where: { date_from: { [Op.lt]: Sequelize.literal('NOW()') } } }; // 浅拷贝目标对象,避免修改原selectA const mergedResult = mergeWithSymbols({...selectA}, selectB); console.log(mergedResult); // 输出:{ where: { text: 'something', date_from: { [Op.lt]: Sequelize.literal('NOW()') } } }
方法2:用Lodash的mergeWith自定义合并逻辑
Lodash其实提供了mergeWith方法,允许你自定义合并规则,我们可以利用它来处理Symbol键:
import { mergeWith } from 'lodash'; import { Op } from 'sequelize'; const selectA = { where: { text: "something" } }; const selectB = { where: { date_from: { [Op.lt]: Sequelize.literal('NOW()') } } }; const mergedResult = mergeWith({}, selectA, selectB, (objValue, srcValue) => { if (typeof srcValue === 'object' && srcValue !== null) { // 先扩展字符串键,再手动复制Symbol键 const mergedObj = {...objValue, ...srcValue}; for (const symKey of Object.getOwnPropertySymbols(srcValue)) { mergedObj[symKey] = srcValue[symKey]; } return mergedObj; } // 非对象类型直接使用默认合并逻辑 }); console.log(mergedResult);
方法3:用Sequelize原生的Op.and组合条件
既然你在用Sequelize,其实可以直接用它的逻辑运算符来组合查询条件,这可能是最符合ORM设计的方式,不用自己合并对象:
import { Op } from 'sequelize'; const selectOptions = { where: { [Op.and]: [ { text: "something" }, { date_from: { [Op.lt]: Sequelize.literal('NOW()') } } ] } };
为什么Lodash的merge会失效?
简单来说,Lodash内部遍历对象属性时,默认只处理可枚举的字符串键,Symbol类型的键不会被包含在默认的遍历逻辑里,所以合并时这些属性就被跳过了,最终变成空对象。
内容的提问来源于stack exchange,提问作者Andrej Leitner
相关产品推荐
相关产品推荐

