【问题标题】:Remove empty properties / falsy values from Object with Underscore.js使用 Underscore.js 从 Object 中删除空属性/虚假值
【发布时间】:2012-12-13 01:13:12
【问题描述】:

我有一个具有多个属性的对象。我想删除任何具有虚假值的属性。

这可以通过数组上的compact 来实现,但是对象呢?

【问题讨论】:

  • 为了避免跨存储库复制粘贴,您可以使用 Bit 到 import this component(它有 3 个测试通过和 MIT 许可证)。你也可以试试this NPM package(这对于一个小组件来说可能有点过头了)。

标签: javascript arrays object underscore.js


【解决方案1】:

从Underscore 1.7.0版本开始,可以使用_.pick:

_.pick(sourceObj, _.identity)

说明

_.pick 的第二个参数可以是用于选择值的谓词函数。选择谓词返回 truthy 的值,忽略谓词返回 falsy 的值。

pick _.pick(object, *keys)

返回 object 的副本,过滤后仅包含列入白名单的 keys(或有效键的数组)的值。或者接受一个谓词,指示选择哪些键。

_.identity 是一个辅助函数,它返回它的第一个参数,这意味着它也可以作为一个谓词函数来选择真值并拒绝假值。 Underscore 库还附带了许多其他谓词,例如 _.pick(sourceObj, _.isBoolean) 将只保留布尔属性。

如果你经常使用这种技术,你可能想让它更有表现力:

var pickNonfalsy = _.partial(_.pick, _, _.identity); // Place this in a library module or something
pickNonfalsy(sourceObj);

下划线版本 1.6.0 也提供了 _.pick,但它不接受谓词函数而不是白名单。

【讨论】:

  • 特别感谢提到_.identity功能,非常好用。
  • 这非常方便!也可以使用_.omit(sourceObj, _.isUndefined) 仅删除未定义的值(允许 false、null、0)。
  • 也可以使用pick(obj, Boolean) 来消除错误值,这与arr.filter(Boolean) 从错误值中清除数组时可以使用相同的方法...
  • 在 ES6 中,这变成了_.pick(sourceObj, prop => prop)
  • 在 lodash 4.4.0 _.pick 与属性名称一起使用,对于帖子使用中提到的此功能_.pickBy
【解决方案2】:

您可以制作自己的下划线插件(mixin):

_.mixin({
  compactObject: function(o) {
    _.each(o, function(v, k) {
      if(!v) {
        delete o[k];
      }
    });
    return o;
  }
});

然后将其用作原生下划线方法:

var o = _.compactObject({
  foo: 'bar',
  a: 0,
  b: false,
  c: '',
  d: null,
  e: undefined
});

更新

作为@AndreiNeculaupointed out,这个mixin影响了原来的对象,而原来的compact下划线方法returns a copy of the array。
为了解决这个问题并让我们的compactObject 表现得更像它的表亲,这里有一个小的更新:

_.mixin({
  compactObject : function(o) {
     var clone = _.clone(o);
     _.each(clone, function(v, k) {
       if(!v) {
         delete clone[k];
       }
     });
     return clone;
  }
});

【讨论】:

  • 由于问题有一个下划线引用,最好提一下它的行为不像_.compact。它将删除属性,而不是创建仅具有真实值的浅层克隆。请参阅下面的stackoverflow.com/a/19750822/465684
  • @AndreiNeculau 你是对的!我之前好像错过了。请参阅我的更新答案。
  • 为什么要先复制一个对象的所有属性,然后循环遍历它们并删除虚假的?这表现不佳。此外,通常不鼓励使用delete,因为它会立即从原型链中公开具有相同名称的属性,并且还会由于“隐藏类”(V8)而损害性能 - 更改对象结构会导致引擎做额外的工作。最好和最短的解决方案是_.pick(o, _.identity)。
【解决方案3】:

快速清除:_.omitBy( source, i => !i );

这与 Emil 的回答相反。这样,恕我直言,读起来更清楚;它更自我解释。

如果你没有 ES6 的奢华,那么干净一点:_.omitBy( source, function(i){return !i;});

备用:_.omitBy( source, _.isEmpty)

使用 _.isEmpty,而不是 _.identity 来保证真实性,还可以方便地从集合中删除空数组和对象,并且可能不方便地删除数字和日期。因此,结果不是对 OP 问题的确切答案,但是在寻找删除空集合时它可能很有用。

【讨论】:

  • 在 Lodash 4.0 中,此功能现在位于 omitBy 下。 lodash.com/docs#omitBy
  • 我相信这与:_.pick(source, i => i); 避免否定
  • @JeffLowery 这在 Lodash 中更好,因为默认谓词是恒等函数! _.pickBy(source) 就足够了。
  • 注意:数字被认为是空的。 _.isEmpty(5) === true。因此,数字值将被删除。
【解决方案4】:

用lodash的transform,

_.transform(obj, function(res, v, k) {
  if (v) res[k] = v;
});

【讨论】:

  • whit lodash 的 _.pick(obj, _.identity);短^_^
  • 这个答案或@evilive在它下面的评论就是答案。
  • 根据上述评论,一个较短的变体是var compactObject = _.partialRight(_.pick, _.identity);
  • 是的,_.pickBy(object) 就是你所需要的
【解决方案5】:
Object.keys(o).forEach(function(k) {
    if (!o[k]) {
        delete o[k];
    }
});

【讨论】:

【解决方案6】:

你可以创建一个浅克隆:

_(obj).reduce(function(a,v,k){ 
     if(v){ a[k]=v; } 
     return a; 
},{});

【讨论】:

    【解决方案7】:

    对于对象使用删除。

    for(var k in obj){
    
      if(obj.hasOwnProperty(k) && !obj[k]){
        delete obj[k];
      }
    }
    

    【讨论】:

    • 因为他想要一个下划线解决方案,您可以使用下划线的方法之一迭代数组
    【解决方案8】:

    突然间,我需要创建一个函数来递归地删除 falsies。我希望这有帮助。我正在使用 Lodash。

    var removeFalsies = function (obj) {
        return _.transform(obj, function (o, v, k) {
            if (v && typeof v === 'object') {
                o[k] = _.removeFalsies(v);
            } else if (v) {
                o[k] = v;
            }
        });
    };
    
    _.mixin({ 'removeFalsies': removeFalsies });
    

    然后就可以使用了:

    var o = _.removeFalsies({
      foo: 'bar',
      a: 0,
      b: false,
      c: '',
      d: null,
      e: undefined,
      obj: {
        foo: 'bar',
        a: 0,
        b: false,
        c: '',
        d: null,
        e: undefined
      }
    });
    
    // {
    //   foo: 'bar',
    //   obj: {
    //     foo: 'bar'
    //   }
    // }
    

    【讨论】:

      【解决方案9】:

      添加到 gion_13 的答案:

      _.mixin({
        compactObject : function(o) {
           var newObject = {};
           _.each(o, function(v, k) {
             if(v !== null && v !== undefined) {
               newObject[k] = v
             }
           });
           return newObject;
        }
      });
      

      这会创建一个新对象并添加键和值,而不是克隆所有内容并删除键值对。细微差别。

      但更重要的是,显式检查 null 和 undefined 而不是 false,这将删除具有 false 作为值的键值对。

      【讨论】:

        【解决方案10】:

        您应该使用来自 lodash 的 pickBy。

        pickBy 的默认签名是_.(sourceObj, [_.identity]),所以它会删除空属性

        _.pickBy(sourceObj);
        

        【讨论】:

          【解决方案11】:

          在 lodash 你这样做:

          _.pickBy(object, _.identity);
          

          【讨论】:

            【解决方案12】:

            尽管_.compact 已记录在数组中使用。它似乎也适用于对象。我刚刚在 chrome、opera 和 firefox 控制台中运行了以下命令:

            var obj = {first: 1, second: null, third: 3, fourth: function(){return 5}}
            undefined
            _.compact(obj)
            
            [1, 3, function()]
            

            更新:如示例所示,对对象调用 _.compact 将删除键并返回压缩数组。

            【讨论】:

            • 但它仍然返回一个数组。钥匙丢了。
            • 你是对的。那我要删除我的答案吗?还是 stackoverflow 更喜欢别的东西?
            • 我不知道社区偏好,但如果您愿意离开,它可能具有防止其他人添加类似答案的价值。
            猜你喜欢
            • 2019-05-23
            • 2015-12-30
            • 1970-01-01
            • 2018-10-05
            • 1970-01-01
            • 2016-07-01
            相关资源
            最近更新 更多