gpt4 book ai didi

javascript - 使用 Object.assign 或类似的扩展数组而不是覆盖数组的模式

转载 作者:行者123 更新时间:2023-11-30 11:35:17 25 4
gpt4 key购买 nike

我正在寻找一个关于如何确定何时覆盖或扩展数组/集合的通用解决方案。

假设我们有这个对象:

let obj1 = {

rolo: 'bar',
yolo: true,
cholo: [1,2,3,4]

};

如果我打电话

let obj2 = Object.assign({}, obj1, {
cholo: [5]
});

我会得到这个:

   obj2 => { rolo: 'bar', yolo: true, cholo: [ 5 ] }

但我要找的是:

  obj2 => { rolo: 'bar', yolo: true, cholo: [ 1, 2, 3, 4, 5 ] }

允许扩展数组而不是覆盖的最佳模式是什么?我对在库代码的上下文中执行此操作特别感兴趣。用户可以在这里选择是扩展数组还是覆盖数组。

我知道没有简单或简单的模式可以用来做到这一点。

例如,我们可以这样做:

  override: {

metadata:{
cholo: {
extend: true
}
},

value: {
cholo: [5]
}
}

添加一些元数据以配合新对象。然后我会有一些自定义函数,它不仅会调用 Object.assign,还会检查元数据属性,并手动复制属性。

像这样:

let copier = function(defaultObj, {value, metadata}){

let allKeysDupes = Object.keys(value).concat(Object.keys(defaultObj));
let allKeys = allKeysDupes.filter(i => allKeysDupes.indexOf(v === i));
let ret = {};

// manually go through all keys
// check metadata to determine whether to overwrite or extend arrays, etc.

allKeys.forEach(function(k){

if(metadata[k]{
// check the metadata and follow it's rules


}
else if(k in val){
ret[k] = val[k];
}
else {
ret[k] = defaultObj[k];
}

});

return ret;
}

最佳答案

使用 ES6 代理的通用解决方案

以下是利用 ES6 Proxies 的通用解决方案(在 ECMAScript 2015 Language Specification (ES6) 中引入)对传递给它的任何普通对象执行可定制的深度合并和串联。此函数允许为遇到的每种类型的输入值轻松自定义合并过程,并且应该能够处理任何类型的输入值,只要它传递的对象通常与 Object.assign() 一起工作即可。 .


解释

准确获取类型

为了处理目的,轻松准确地识别输入值的类型非常重要。为此,函数利用 Object.prototype.toString哪个(当针对任意值调用时)将返回一个类似于 [object String] 的字符串或 [object Object] , 等。从那里我们可以去掉不必要的位,得到一个类似 String 的字符串。或 Object

const gettype = e => Object.prototype.toString.call(e).replace(/.*\b(\w+)./, '$1');

处理处理程序

我们需要简化对不同数据类型的处理。您可以使用凌乱的、硬编码的 switch 语句,但我更喜欢更流畅的东西。我喜欢使用函数对象。对于我们要处理的每种类型,我们只需定义一个与 gettype 的输出直接匹配的属性名称。上面定义的函数。然后在需要的时候,我们可以根据对应的类型值查找那个函数。

在这个例子中,我创建了一组默认的处理程序,然后由函数的第一个参数中提供的处理程序覆盖。

Object.assign(h, {
"Array": (a, b) => [...a, ...b],
"Object": (a, b) => deepmerge(h, a, b),
"Set": (a, b) => new Set([...a, ...b]),
"Map": (a, b) => {
const o = new Map([...a]);
for(let [k,v] of [...b]) {
const vt = gettype(v);
o.set(k, a.has(k) && vt in h ? h[vt](a.get(k), v) : v);
}
return o;
}
}, h);

使用代理拦截设置操作

现在我们将进入代理部分。首先定义一个“out”对象。该对象是该函数最终将返回的对象,并将作为代理的目标。

const o = {};

接下来使用设置的陷阱为“out”对象创建一个代理。当设置操作发生时,设置陷阱将原始值和新值传递给适当的设置处理程序。如果没有合适的设置处理程序,它会用新值覆盖旧值。确定的值应用于“out”对象。

const p = new Proxy(o, {
set: (o, k, b) => {
const a = o[k];
const at = gettype(a);
return (o[k] = (at in h && k in o ? h[at](a, b) : b), true);
}
});

下次使用Object.assign将对象合并到代理中,这会触发上面为每个设置操作定义的设置陷阱。

Object.assign(p, ...args);

最后返回“out”对象。

return o;

完整定义

const deepmerge = (h, ...args) => {
const gettype = e => Object.prototype.toString.call(e).replace(/.*\b(\w+)./, '$1');

const o = {};

Object.assign(h, {
"Array": (a, b) => [...a, ...b],
"Object": (a, b) => deepmerge(h, a, b),
"Set": (a, b) => new Set([...a, ...b]),
"Map": (a, b) => {
const o = new Map([...a]);
for(let [k,v] of [...b]) {
const vt = gettype(v);
o.set(k, a.has(k) && vt in h ? h[vt](a.get(k), v) : v);
}
return o;
}
}, h);

const p = new Proxy(o, {
set: (o, k, b) => {
const a = o[k];
const at = gettype(a);
return (o[k] = (at in h && k in o ? h[at](a, b) : b), true);
}
});

Object.assign(p, ...args);

return o;
};

用法

deepmerge(handlers, ...sources)
  • 处理程序

    处理程序对象。处理程序对象可用于覆盖给定类型的默认处理程序,或为默认情况下未处理的类型提供处理程序。

    示例:

    {
    "String": (a, b) => a + b,
    "Number": (a, b) => a + b,
    }
    • 每个属性的名称应该是正在处理的类型的名称,首字母大写。
    • 每个属性的值应该是一个函数,它接受两个参数并返回合并这些参数的结果。
  • 来源

    正在合并的对象。
    • 每个被合并的对象都必须是一个普通对象(没有映射、集合或数组等)。
    • 每个对象都可以包含任何类型的值。

例子

以下片段显示了两个示例:

  • 第一个只使用默认处理程序
  • 第二个使用一些自定义处理程序来演示合并过程的自定义。请注意两个结果对象的差异。

const objects = [
{
string: "hello",
number: 1,
boolean: true,
array: [1,2,3],
object: { a: 1, b: 2 },
map: new Map([[1,2],[2,3],[4,2],[undefined, undefined],[null, null]]),
set: new Set([1,2,3]),
null: null,
undefined: undefined
},
{
string: " world",
number: 2,
boolean: false,
array: [4,5,6],
object: { a: 2, b: 1 },
map: new Map([[1,1],[2,0],[3,1],[undefined, null],[null, undefined]]),
set: new Set([4,5,6]),
null: undefined,
undefined: null
}
];

console.log(deepmerge({}, ...objects));
console.log(deepmerge({
"String": (a, b) => a + b,
"Number": (a, b) => a + b,
}, ...objects));
<script src="https://cdn.rawgit.com/Tiny-Giant/43cc03adf3cdc84ff935655cbebbe585/raw/754070ca8858efeff5a2c3b8bad6475842565798/deepmerge.js"></script><link rel="stylesheet" href="https://cdn.rawgit.com/Tiny-Giant/f2a53f469863baadf1b4ad48a4b4ea39/raw/b0ede74f374199abe9324334d1c0ef088a850415/deepmerge.css" type="text/css">

关于javascript - 使用 Object.assign 或类似的扩展数组而不是覆盖数组的模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44739990/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com