JavaScript通过使用另一个对象作为选择器来删除对象属性

JavaScript通过使用另一个对象作为选择器来删除对象属性,javascript,object,recursion,Javascript,Object,Recursion,我有这样的目标: var myObj = { first: { sub: { prop1: "some text", prop2: "some more text" }, sub2: { prop1: "Something", prop2: "Something2", } }, second: {

我有这样的目标:

var myObj = {
    first: {
        sub: {
            prop1: "some text",
            prop2: "some more text"
        },
        sub2: {
            prop1: "Something",
            prop2: "Something2",
        }
    },
    second: {
        stuff: "More stuff...lots of stuff"
    }
}
我试图通过使用另一个对象作为选择器来删除此对象的属性。例如:

var delSeletor = {
    first: {
        sub: {
            prop2: ""
        }
    }
}
因此
delete(delSelector,myObject)
应该返回:

var myObj = {
    first: {
        sub: {
            prop1: "some text",
        },
        sub2: {
            prop1: "Something",
            prop2: "Something2",
        }
    },
    second: {
        stuff: "More stuff...lots of stuff"
    }
}

请注意,我不是在寻找使用“.dot”选择器的解决方案,例如:
delete('first.sub.prop2',myObj)
,如图所示。

您可以迭代对象
选择器
,以获取要删除的键并进行检查

  • 如果密钥不存在,则返回
  • 如果选择器对象的属性是对象,则使用键再次调用delete函数
    deleteKeys
    。否则,从源对象中删除密钥
函数删除键(对象、选择器){
Object.keys(选择器).forEach(函数(k){
如果(!(对象中的k)){
返回;
}
if(选择器的类型[k]=“对象”){
删除键(对象[k],选择器[k]);
}否则{
删除对象[k];
}
});
}
var myObj={first:{sub:{prop1:{some text],prop2:{some more text},sub2:{prop1:“Something”,prop2:“Something 2”,},第二:{stuff:{stuff:“more stuff…lot stuff”},
delSeletor={first:{sub:{prop2::}}};
删除键(myObj、delSeletor);
console.log(myObj)

.as控制台包装{max height:100%!important;top:0;}
这是一个使用函数编程的版本,它使用
map
reduce

它递归地遍历对象并删除在对象上用表示删除的空字符串标记的键

function deleteKeys(deletions, obj) {
    if (deletions === "") {
        return null
    }
    return Object
        .keys(obj)
        .map(key => {
            if (!(key in deletions)) {
                // if the key is not in the object containing 
                // the keys to delete
                return { [key]: obj[key] };
            }
            //recursively create a filtered object
            const filteredObj = deleteKeys(deletions[key], obj[key])

            // if that object is null, then return an empty object
            // else return the filtered object
            return filteredObj ? { [key]: filteredObj } : {}
        })

        // we now have an array of object that we need to merge together :)
        .reduce((acc, obj) => Object.assign({}, acc, obj), {})
}
以下是我为编写此代码而运行的测试:

const cleanedObj = deleteKeys(
    { first: "" },
    { first: "", second: { hi: ["heelo"] }}
);

console.log(cleanedObj);

const cleanedObj2 = deleteKeys(
    { second: { hi: "" }},
    { first: "", second: { hi: ["heelo"] }}
);

console.log(cleanedObj2);

const cleanedObj3 = deleteKeys(
    { second: "" },
    { first: "", second: { hi: ["heelo"] }}
);

console.log(cleanedObj3);
这个解决方案值得注意的是,它是一个纯函数,这意味着它不会修改初始对象,而是返回一个新对象。FTW无副作用,我们现在用于此类数据处理任务。只要你把头绕在它身上,它就会非常强大。以下是您解决问题的方法

注:

  • 首先,我们扫描第一个选择器对象并提取路径。然后我们使用路径删除相应的目标
  • 这也适用于阵列,只需稍作修改
//const objectScan=require('object-scan');
常量修剪=(选择,输入)=>{
常量指针=对象扫描(['**']{
是的,
filterFn:({value})=>typeof value==='string'
})(sel);
返回对象扫描(针{
rtn:'计数',
filterFn:({parent,property})=>{
删除父项[属性];
}
})(输入);
};
const myObj={first:{sub:{prop1:{some text',prop2:{some more text'},sub2:{prop1:'Something',prop2:'Something 2'},第二:{stuff:'more stuff…lot of stuff'};
const delSeletor={first:{sub:{prop2:''}}};
console.log(prune(delSeletor,myObj));//返回删除计数
// => 1
console.log(myObj);
//=>{first:{sub:{prop1:{some text'},sub2:{prop1:'Something',prop2:'Something2'},第二:{stuff:'More stuff…lots stuff'}
。作为控制台包装{最大高度:100%!重要;顶部:0}

删除意味着相同的对象?选择器总是以根键开始吗?如果
delSelector
是一个数组,不是更简单吗?ie
[“first”、“sub”、“prop2”]
有点像xpath的工作原理。如果您可以使用一段代码将初始对象转换为
符号,然后使用另一个线程中给出的
删除
,会怎么样?这能回答您的问题吗?是的,这意味着从myObj中删除,是的,选择器总是从根键开始(在本例中首先),并按照正确的路径进行操作。@Halcyon&@atomrc我现在正在使用该解决方案,但我正试图找到更高效、更快速的工作解决方案,这将直接在对象级别上工作,而不是将对象选择器转换为数组或
dot
selectorExcellent解决方案,并且初始测试显示了更好的性能。