【问题标题】:Simplest way to copy JS object and filter out certain properties复制 JS 对象并过滤掉某些属性的最简单方法
【发布时间】:2018-03-12 22:35:40
【问题描述】:

如果我有一个 JS 对象,并且我想创建一个新对象来复制所有属性,除了需要过滤掉的属性黑名单,那么最简单的方法是什么?

所以我会做类似的事情

originalObject.copyAndFilter('a', 'b')

这将获取原始对象,复制它,并确保属性 ab 不在新对象中。

我正在通过 Babel 使用 ES2015/2016,所以如果它提供了一种更简单的方法也可以使用。

【问题讨论】:

  • 浅拷贝还是深拷贝?过滤后的键是在任何地方(任何深度)还是仅在第一级?
  • 在简单对象上进行深度复制的一种廉价而简单的方法是 var copy = JSON.parse(JSON.stringify(object)) - 在 javascript Primitives 中,DateSymbolundefined 不会简单地工作......这个只留下布尔值、数字和字符串可以使用这个“hack”——虽然,也有解决方法,但这更像是一个 hack
  • youmightnotneedjquery.com/#deep_extend(或只是扩展),只需在函数签名中添加一个filter 参数(键名数组)并使用if (obj.hasOwnProperty(key) && filter.indexOf(key) < 0)?

标签: javascript ecmascript-6


【解决方案1】:

您可以使用Set 并删除不需要的属性。

var object = { a: 1, b: 2, c: 3, d: 4 },
    filteredObject = {},
    p = new Set(Object.keys(object));
    blacklist = ['a', 'b'];

blacklist.forEach(a => p.delete(a));

[...p].forEach(k => filteredObject[k] = object[k]);
console.log(filteredObject);

【讨论】:

  • 套装有什么帮助?您也可以将其保留为数组并使用.filter()...
  • 我会阻止使用blacklist.includes
  • 这很公平。 +1
【解决方案2】:

嗯,没有简单的本地方法可以做到这一点,我会将键转换为数组,过滤它,然后创建一个新对象:

const obj = {a: 'foo', b: 'bar', c: 'baz'};
const blacklist = ['a', 'b'];

const keys = Object.keys(obj);
const filteredKeys = keys.filter(key => !blacklist.includes(key));

const filteredObj = filteredKeys.reduce((result, key) => {
  result[key] = obj[key];
  return result;
}, {});

console.log(filteredObj);

【讨论】:

    【解决方案3】:

    您可以只循环对象键并创建一个新对象。你甚至可以使用for...in。这将增加所有浏览器都支持的优势。

    var obj = {a: 'foo', b: 'bar', c: 'baz'};
    var blackListKeys = ['a', 'b','z'];
    var obj2 = {}
    for(var k in obj){
      if(blackListKeys.indexOf(k) === -1)
        obj2[k] = obj[k];
    }
    console.log(obj2)

    【讨论】:

      【解决方案4】:

      var obj = {foo: 1, a: 2, b:3}
      var newObj = {}
      var blacklist = ['a', 'b']
      
      for(let [key, value] of Object.entries(obj)) {
        !blacklist.includes(key) && (newObj[key] = value)
      }
      
      console.log(newObj)

      变量更少:

      var obj = {foo: 1, a: 2, b: 3}
      
      var newObj = Object.entries(obj)
        .filter(([key, val]) => !['a', 'b'].includes(key))
        .reduce((newObj, [key, value]) => (newObj[key] = value, newObj), {})
      
      console.log(newObj)

      【讨论】:

        【解决方案5】:

        这里有两个问题:

        第一个实际上是在复制没有引用的对象。

        如果您只是简单地循环对象键并从原始对象执行其值的分配,如果该值也是对象,那么您最终会引用该对象(甚至是数组),而不是复制自身。因此,您需要检测并递归调用您的 copy_object 函数以避免引用。

        幸运的是,一些库已经解决了这个问题,这些库提供了对象 extend() 函数,例如 npm(服务器端)和 jQuery(浏览器)。

        技巧只在于扩展新创建的对象:

        var dst_object = extend({}, src_object);
        

        第二个问题是避免不想要的键。

        这里有一些可能的方法:一种是完全重新实现前面提到的 extend() 函数,以提供黑名单功能。

        ...第二个(更不容易出错)是在复制对象后简单地删除不需要的键。如果它们不是巨大的数据结构,那么开销将是微不足道的。

        例子:

        // npm install --save extend
        var extend = require("extend");
        function oClone(target, blacklist) {
            var dest = extend({}, target);
            if (blacklist) {
                for (var i=0; i<blacklist.length; i++) {
                    delete (dest[blacklist[i]]);
                };
            };
            return dest;
        };
        

        【讨论】:

          【解决方案6】:

          我认为 Object.assign 是最好的 ES5 实用程序,几乎不需要额外的逻辑:

          function copyAndFilter(...args){ 
              var copy = Object.assign( {} , this);
          
              args.forEach(prop => { 
                  delete copy[prop];
              }); return copy;
          }
          

          然后:

          var a = {foo : 'foo' , bar : 'bar'};
          a.copyAndFilter = /* function definition above*/
          a.copyAndFilter('foo');// { bar : 'bar' }
          

          【讨论】:

            猜你喜欢
            • 2018-10-12
            • 2010-12-14
            • 2021-12-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-04-21
            • 1970-01-01
            相关资源
            最近更新 更多