对象属性动态删除

13

我很想了解一种更好的方法,基于通配符,动态删除javascript对象中的属性。首先,假设我有以下对象:

object =
{
    checkbox_description_1 : 'Chatoyant',
    checkbox_description_2 : 'Desultory',
    random_property : 'Firefly is a great program',
    checkbox_mood_1 : 'Efflorescent',
    checkbox_description_3 : 'Ephemeral'
}

任务

现在,最终目标是删除所有以“checkbox_description”为幌子的属性,并保留对象的其余部分,如下所示:

object =
{
    random_property : 'Firefly is a great program',
    checkbox_mood_1 : 'Efflorescent',
}

我的解决方案

目前,我的解决方案涉及到jquery和以下代码:

var strKeyToDelete = 'checkbox_description'

/* Start looping through the object */
$.each(object, function(strKey, strValue) {

    /* Check if the key starts with the wildcard key to delete */
    if(this.match("^"+strKey) == strKeyToDelete) {

        /* Kill... */
        delete object[strKey];
    };
});

问题

我觉得这个操作很不优雅,如果对象的大小合理的话,会非常耗费资源。有没有更好的方法来执行这个操作?

4个回答

13

这是必需的最低要求:

function deleteFromObject(keyPart, obj){
    for (var k in obj){          // Loop through the object
        if(~k.indexOf(keyPart)){ // If the current key contains the string we're looking for
            delete obj[k];       // Delete obj[key];
        }
    }
}

var myObject = {
    checkbox_description_1 : 'Chatoyant',
    checkbox_description_2 : 'Desultory',
    random_property : 'Firefly is a great program',
    checkbox_mood_1 : 'Efflorescent',
    checkbox_description_3 : 'Ephemeral'
};
deleteFromObject('checkbox_description', myObject);
console.log(myObject);
// myObject is now: {random_property: "Firefly is a great program", checkbox_mood_1: "Efflorescent"};
这与您拥有的jQuery函数非常接近。考虑到它不使用jQuery,而是使用indexOf而不是match,因此速度略快一些。
那么,为什么在indexOf之前要加上“~”呢?
indexOf返回一个整数值:如果未找到字符串,则为-1,如果找到,则为从0开始的索引(因此如果找到,则始终为正整数)。 “〜”是按位“NOT”,可以反转这个输出。恰好相反的是,indexOf的反转输出正是我们需要指示“找到”或“未找到”的内容。
“〜-1”变成“0”,即伪造的假值。 “〜x”,其中x为0或正整数,变成“-(x + 1)”,即伪造的真值。
这样,~string.indexOf('needle')就像string.contains('needle')一样,这是JavaScript中没有的函数。
另外,你可以在“〜”前面添加一个双重布尔否定(!!),将真伪输出转换为真/假,但在JavaScript中这并不必要。 从功能上讲,“~string.indexOf('needle')”和“!!~string.indexOf('needle')”是相等的。
如果您特别需要key以needle开头,请替换:
~k.indexOf(keyPart)

随着:

k.indexOf(keyPart) === 0

1
也许值得解释一下这里的~是什么意思——在JavaScript中,它不是一个常见的运算符。 - Jamiec
如果关键部分在索引0处怎么办? - Jonathan de M.
@JonathandeM.:这就是 ~ 的作用。 - Cerbrus
@Cerbrus。不错的+1!(应该是“当x为零或正数时”) - Jamiec
1
OP 是否想要键以通配符字符串开头,而不是包含它? - Bergi
显示剩余2条评论

8
    var myObject = {
        checkbox_description_1 : 'Chatoyant',
        checkbox_description_2 : 'Desultory',
        random_property : 'Firefly is a great program',
        checkbox_mood_1 : 'Efflorescent',
        checkbox_description_3 : 'Ephemeral'
   };

const removeProperty = dyProps => ({ [dyProps]: _, ...rest }) => rest;

const remove_random_property = removeProperty('random_property');
console.log(remove_random_property(myObject));

3

我不禁想知道indexOfsubstr是否在幕后使用相同的算法,只是indexOf搜索每个索引,而不仅仅是用substr指定的一个。这将使非匹配更加高效。 - Ian
是的,这就是使用 substr 的目的 :-) 我认为你不能比较算法,因为 substr 不会搜索。当然,更好的实现不会提取整个 substr,而是逐个字符进行比较,这样可以尽早中断。 - Bergi
我想表达的是,我在想indexOf是否会一遍又一遍地使用substr(或类似的算法),从索引0length-1(也许在不必要进行搜索的某个点之后就停止搜索)。比如说,如果indexOf有第二个参数,表示在哪个索引处停止搜索……如果你传递了1,那么它将与在此“starting with”示例中使用substr是“相同”的。我不确定逐个字符比较是否在工作量方面更好,但至少更有意义。 - Ian
indexOf有第二个参数,用于指定开始搜索的位置。是的,从那里开始它会逐个字符地进行比较;一旦不匹配,它就会从下一个索引开始尝试。 - Bergi
我忘记了实际的第二个参数!那么我是指第三个参数!无论如何,这只是假设。我想你明白了。但没关系 :) - Ian

1
如果您正在寻找不会改变原始对象的解决方案,可以尝试类似以下的方法。
const omit = (source = {}, omitKeys = []) => (
  Object.keys(source).reduce((output, key) => (
    omitKeys.includes(key) ? output : {...output, [key]: source[key]}
  ), {})
)

测试

const original = {a:1, b:2, c:3, d:4, e:5}
console.log('original: ', JSON.stringify(original));

const modified = omit(original, ['b', 'd'])
console.log('modified: ', JSON.stringify(modified));
console.log('original: ', JSON.stringify(original));

// Will log: 
// original: {"a":1,"b":2,"c":3,"d":4,"e":5}
// modified: {"a":1,"c":3,"e":5}
// original: {"a":1,"b":2,"c":3,"d":4,"e":5}

这将创建一个新对象,并将源对象的所有属性扩展到其中,除了在排除列表(omitKeys)中包含的属性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接