JavaScript使用另一个对象作为选择器深度删除对象属性

时间:2017-06-01 11:52:22

标签: javascript object recursion

我有这样的对象:

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),如thread所示。

3 个答案:

答案 0 :(得分:3)

您可以迭代对象selector以删除和检查

的键
  • 如果密钥不存在,请返回
  • 如果选择器对象的属性是对象,则使用该键再次调用删除函数deleteKeys。否则,从源对象中删除密钥。

function deleteKeys(object, selector) {
    Object.keys(selector).forEach(function (k) {
        if(!(k in object)) {
            return;
        }
        if (typeof selector[k] === 'object') {
            deleteKeys(object[k], selector[k]);
        } else {
            delete object[k];
        }
    });
}

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

deleteKeys(myObj, delSeletor);

console.log(myObj);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:0)

这是一个使用mapreduce的函数式编程的版本。

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

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);

值得注意的是这个解决方案,它是一个纯函数https://en.wikipedia.org/wiki/Pure_function),这意味着它不会修改你的初始对象而是返回一个新对象。无副作用FTW

答案 2 :(得分:0)

我们现在将object-scan用于此类数据处理任务。一旦将头缠绕在它上,它就会非常强大。这是解决问题的方法。

注意:

  • 首先,我们扫描第一个选择器对象并提取路径。然后,我们使用路径删除相应的目标。
  • 这同样适用于数组,只需稍加修改即可
const objectScan = require('object-scan');

const prune = (sel, input) => {
  const needles = objectScan(['**'], {
    joined: true,
    filterFn: ({ value }) => typeof value === 'string'
  })(sel);
  return objectScan(needles, {
    rtn: 'count',
    filterFn: ({ parent, property }) => {
      delete parent[property];
    }
  })(input);
};

const myObj = {
  first: {
    sub: { prop1: 'some text', prop2: 'some more text' },
    sub2: { prop1: 'Something', prop2: 'Something2' }
  },
  second: { stuff: 'More stuff...lots of stuff' }
};

const delSeletor = { first: { sub: { prop2: '' } } };

console.log(prune(delSeletor, myObj)); // return deletion counts
// => 1
console.log(JSON.stringify(myObj));
// => {"first":{"sub":{"prop1":"some text"},"sub2":{"prop1":"Something","prop2":"Something2"}},"second":{"stuff":"More stuff...lots of stuff"}}