【问题标题】:Deep Filter Of Object Properties对象属性的深度过滤
【发布时间】:2015-04-25 06:37:32
【问题描述】:

我正在寻找一种能够根据某种数据格式过滤对象属性的方法。假设我有一个这样的对象:

var data = {
  name : {
    first : "Sam",
    last : "Wise",
    invalid : "Not A Valid Property"
  },
  address : "210 Test St.",
  city : "Springfield",
  state : "CA",
  zip : "65565",
  invalid_key1: "Something invalid",
  invalid_key2: "Another invalid one"
}

理想情况下,我想创建一个方法来深入检查每个属性,只允许过滤对象中存在的键。我有一个适用于浅对象的版本,但是我还没有想出一个聪明的方法来为子对象/数组做这件事。

var controlObject = {
  'name' : {
    first : true,
    last : true
  },
  'address' : true,
  'city' : true,
  'state' : true,
  'zip' : true
};

filterObj(data, controlObject);
// Would return:
// {
//   name : {
//     first : "Sam",
//     last : "Wise"
//   },
//   address : "210 Test St.",
//   city : "Springfield",
//   state : "CA",
//   zip : "65565"
// }

这是我当前的版本,它只检查一层深度。

_.mixin({
    filterObj : function(data, control) {
    // First set some defaults.
    var _data = data || {};
    var _control = control || {};

    // Create arguments to be passed to _.pick()
    var controlKeys = Object.keys(_control);
    var args = [_data].concat(controlKeys);

    // Finally use _.pick() to filter object properties.
    return _.pick.apply(_, args);
  }
});

我试图做一些小技巧让它检查更深层次的对象,但它似乎没有正确地做到这一点。

_.mixin({ 
  filterObj : function(data, control) {
    // First set some defaults.
    var _data = data || {};
    var _control = control || {};

    // Create arguments to be passed to _.pick()
    var controlKeys = Object.keys(_control);
    var args = [_data].concat(controlKeys);

    // Finally use _.pick() to filter object properties.
    var results = _.pick.apply(_, args);

    var moreKeys = Object.keys(_control).filter(function(key) {
      return ( _data[key] == "object" || _data[key] == "array" ) ? true : false
    });

    if( moreKeys.length ) {
      _.each(moreKeys, function(key) {
        results[key] = _.filterObj(_data[key], _control[key]);
      });
      return results;
    } else {
      return results;
    }
  }
});

目前它被设置为一个 Underscore mixin,虽然我并没有接受这个概念(只是让它更容易在我的应用程序中使用)。

【问题讨论】:

    标签: javascript underscore.js


    【解决方案1】:

    我知道这个帖子已经有两年了,但我和你有类似的要求。除了你,我手头没有 Lodash / Underscore,所以我想出了一个纯 JavaScript 解决方案:

    function filterObj(data, control) {
      var controlKeys = Object.keys(control),
        results = controlKeys.reduce(function(v, key) {
          if (control[key] === true && data.hasOwnProperty(key)) {
            v[key] = data[key];
          }
    
          return v;
        }, {});
    
      controlKeys.filter(function(key) {
        return typeof control[key] === 'object' && control[key] !== null && !Array.isArray(control[key]) && typeof data[key] === 'object' && data[key] !== null && !Array.isArray(data[key]);
      }).forEach(function(key) {
        results[key] = filterObj(data[key], control[key]);
      });
    
      return results;
    }
    
    var data = {
      name: {
        first: 'Sam',
        last: 'Wise',
        invalid: 'Not A Valid Property'
      },
      gender: 'm',
      password: 'abc123',
      location: {
        address: '210 Test St.',
        city: 'Springfield',
        state: 'CA',
        zip: '65565'
      },
      invalid_key1: 'Something invalid',
      invalid_key2: 'Another invalid one'
    }
    
    var controlObject = {
      name: {
        first: true,
        last: true
      },
      gender: true,
      password: false,
      location: true
    };
    
    console.log(filterObj(data, controlObject));

    请注意我改变了你最初方法的一些逻辑:

    • 必须将选项标记为 true 以免被过滤掉(严格比较)
    • 可以标记整个(子)对象以将其包含在结果中

    希望这对其他人也有帮助。

    【讨论】:

    • 我知道这会违反 SO 评论政策,但干得好! :thumbup:
    【解决方案2】:

    线

    return ( _data[key] == "object" || _data[key] == "array" ) ? true : false
    

    是你的问题。您缺少 typeof 运算符,并且 js 中没有 "array" 类型 - 所有数组都是对象。无论如何,我认为您的函数不会在数组上按预期工作。更好用

    return (typeof _data[key] == "object") && (_data[key] !== null) && !_.isArray(_data[key]);
    

    【讨论】:

    • 是的,我完全错过了那里的 typeof 声明,最后一次尝试是我在几分钟内完成的。
    【解决方案3】:

    如果你可以使用 Lodash+Deepdash:

    var filtrate = _.filterDeep(data, function(value, key, parent, ctx) {
      return _.has(controlObject, ctx.path);
    });
    

    这是一个完整的test 用于您的案例

    【讨论】:

      猜你喜欢
      • 2015-02-20
      • 2020-08-02
      • 1970-01-01
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 2021-10-28
      • 2019-01-29
      相关资源
      最近更新 更多