在ES6中按键过滤对象属性

29e*_*9er 200 filter ecmascript-6

让我们说我有一个对象:

{
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}
Run Code Online (Sandbox Code Playgroud)

我想通过过滤上面的对象来创建另一个对象,所以我有类似的东西.

 {
    item1: { key: 'sdfd', value:'sdfd' },
    item3: { key: 'sdfd', value:'sdfd' }
 }
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种使用Es6实现这一目标的简洁方法,因此我可以使用扩展运算符.谢谢!

ssu*_*ube 386

如果您有允许值列表,则可以使用以下命令轻松地将它们保留在对象中:

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.keys(raw)
  .filter(key => allowed.includes(key))
  .reduce((obj, key) => {
    obj[key] = raw[key];
    return obj;
  }, {});

console.log(filtered);
Run Code Online (Sandbox Code Playgroud)

这用于:

  1. Object.keys列出raw(原始数据)中的所有属性,然后
  2. Array.prototype.filter 使用选择允许列表中存在的键
    1. Array.prototype.includes 确保他们在场
  3. Array.prototype.reduce 仅使用允许的属性构建新对象.

这将使用允许的属性进行浅表复制(但不会复制属性本身).

您还可以使用对象扩展运算符来创建一系列对象而不会改变它们(感谢rjerue提到这一点):

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.keys(raw)
  .filter(key => allowed.includes(key))
  .reduce((obj, key) => {
    return {
      ...obj,
      [key]: raw[key]
    };
  }, {});

console.log(filtered);
Run Code Online (Sandbox Code Playgroud)

出于琐事的目的,如果你想从原始数据中删除不需要的字段(我建议这样做,因为它涉及一些丑陋的突变),你可以includes像这样反转检查:

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

Object.keys(raw)
  .filter(key => !allowed.includes(key))
  .forEach(key => delete raw[key]);

console.log(raw);
Run Code Online (Sandbox Code Playgroud)

我将此示例包含在内,以显示基于突变的解决方案,但我不建议使用它.

  • 我不能投票这个!做得好用于使用过滤器和减少而不是从for循环构造另一个对象.并且您明确地将不可变版本和可变版本分开了很棒.+1 (3认同)
  • 快速警告:`Array.prototype.includes`不是ES6的一部分.它在ECMAScript 2016(ES7)中引入. (3认同)
  • 如果你想以不可变的方式进行reduce,你也可以用return {... obj,[key]:raw [key]}替换函数内容. (3认同)
  • 解构将起作用(很好),但纯粹是编译时.您不能使其成为动态的属性列表或提供任何复杂的规则(例如,循环可以附加验证回调). (2认同)

Rya*_* H. 67

如果您是使用ES6语法OK,我发现,最干净的方式来做到这一点,因为注意到这里这里是:

const data = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const { item2, ...newData } = data;
Run Code Online (Sandbox Code Playgroud)

现在,newData包含:

{
  item1: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};
Run Code Online (Sandbox Code Playgroud)

或者,如果您将密钥存储为字符串:

const key = 'item2';
const { [key]: _, ...newData } = data;
Run Code Online (Sandbox Code Playgroud)

在后一种情况下,[key]转换为item2但由于您使用的是const赋值,因此需要为赋值指定名称._代表一个扔掉的价值.

更普遍:

const { item2, ...newData } = data; // Assign item2 to item2
const { item2: someVarName, ...newData } = data; // Assign item2 to someVarName
const { item2: _, ...newData } = data; // Assign item2 to _
const { ['item2']: _, ...newData } = data; // Convert string to key first, ...
Run Code Online (Sandbox Code Playgroud)

这不仅会减少您对单行的操作,而且还不需要您知道其他键是什么(您想要保留的那些键).

  • "`_`代表一个扔掉的价值"这是怎么来的?我第一次看到它 (4认同)
  • 我相信这是JS社区采用的惯例.一个`_`只是一个可以在JS中使用的有效变量名,但由于它几乎没有名字,所以如果你想传达意图,它真的不应该以这种方式使用.因此,它被用来表示一个你不关心的变量.以下是对它的进一步讨论:/sf/ask/798477641/ (4认同)
  • 这比接受的答案要整洁得多,避免了使用Object.keys()创建新数组的开销,以及避免了使用`filter`和`reduce`迭代数组的开销。 (2认同)
  • @yhabib的`_`没关系,它只是一个变量名,你可以将它重命名为你想要的任何东西 (2认同)
  • @Gerrat 我不认为通用的解决方案是微不足道的单行。为此,我将使用 lodash 的 `omit` 函数:https://lodash.com/docs/4.17.10#omit 或此处给出的其他解决方案之一。 (2认同)

Guy*_*gev 38

最简单的方法是使用Lodash#pick

const _ = require('lodash');

const allowed = ['item1', 'item3'];

const obj = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

const filteredObj = _.pick(obj, allowed)
Run Code Online (Sandbox Code Playgroud)

  • 需要指出的是,必须在运行时下载额外的项目依赖项。 (5认同)
  • _.omit(obj, ["item2"]) - lodash.omit 与 lodash.pick 相反 (2认同)

小智 30

基于这两个答案:

/sf/answers/3925699361/
/sf/answers/3848369941/

我们可以做的:

const original = { a: 1, b: 2, c: 3 };
const allowed = ['a', 'b'];

const filtered = Object.fromEntries(allowed.map(k => [k, original[k]]));
Run Code Online (Sandbox Code Playgroud)

哪个更干净、更快:

https://jsbench.me/swkv2cbgkd/1


Cle*_*elm 18

没有什么是以前没有说过的,而是将一些答案与一般的ES6答案结合起来:

const raw = {
  item1: { key: 'sdfd', value: 'sdfd' },
  item2: { key: 'sdfd', value: 'sdfd' },
  item3: { key: 'sdfd', value: 'sdfd' }
};

const filteredKeys = ['item1', 'item3'];

const filtered = filteredKeys
  .reduce((obj, key) => ({ ...obj, [key]: raw[key] }), {});

console.log(filtered);
Run Code Online (Sandbox Code Playgroud)

  • 这是一个比其他解决方案更简单、更高效的解决方案;) (4认同)
  • 很好的简洁解决方案。请注意,如果“filteredKeys”中有一个键不在“raw”中,则该键将显示在“filtered”中,且值为“undefined”。在其他答案中,该密钥根本不会出现在“filtered”中。 (3认同)

Nov*_*ovy 18

只是一行代码中的另一种解决方案.

我正在玩" 解构 "功能:

const raw = {
    item1: { key: 'sdfd', value: 'sdfd' },
    item2: { key: 'sdfd', value: 'sdfd' },
    item3: { key: 'sdfd', value: 'sdfd' }
  };
var myNewRaw = (({ item1, item3}) => ({ item1, item3 }))(raw);
console.log(myNewRaw);
Run Code Online (Sandbox Code Playgroud)

  • 这是恕我直言的首选现代方法 (3认同)
  • `var myNewRaw =(({item1,item3})=>({item1,item3}))(raw);`语法问题 (2认同)
  • [接受的答案](/sf/answers/2712562681/)将仅包含过滤器列表中且存在于原始数据中的键。我相信您的答案将插入缺失的键,并将“undefined”作为值,例如,如果我的原始数据不包含“item3”,我认为您的代码会添加它。可能在某些用例中这是不受欢迎的。(对于我的用例来说,这很好!我正在使用它!) (2认同)

Tha*_*you 9

您可以添加泛型ofilter(使用泛型实现oreduce),这样您就可以像使用数组一样轻松地过滤对象 -

const oreduce = (f, acc, o) =>
  Object
    .entries (o)
    .reduce
      ( (acc, [ k, v ]) => f (acc, v, k, o)
      , acc
      )

const ofilter = (f, o) =>
  oreduce
    ( (acc, v, k, o)=>
        f (v, k, o)
          ? Object.assign (acc, {[k]: v})
          : acc
    , {}
    , o
    )
Run Code Online (Sandbox Code Playgroud)

我们可以看到它在这里工作 -

const data =
  { item1: { key: 'a', value: 1 }
  , item2: { key: 'b', value: 2 }
  , item3: { key: 'c', value: 3 }
  }

console.log
  ( ofilter
      ( (v, k) => k !== 'item2'
      , data
      )
      // [ { item1: { key: 'a', value: 1 } }
      // , { item3: { key: 'c', value: 3 } }
      // ]

  , ofilter
      ( x => x.value === 3
      , data
      )
      // [ { item3: { key: 'c', value: 3 } } ]
  )
Run Code Online (Sandbox Code Playgroud)

在下面的浏览器中验证结果 -

const oreduce = (f, acc, o) =>
  Object
    .entries (o)
    .reduce
      ( (acc, [ k, v ]) => f (acc, v, k, o)
      , acc
      )

const ofilter = (f, o) =>
  oreduce
    ( (acc, v, k, o)=>
        f (v, k, o)
          ? Object.assign (acc, { [k]: v })
          : acc
    , {}
    , o
    )

const data =
  { item1: { key: 'a', value: 1 }
  , item2: { key: 'b', value: 2 }
  , item3: { key: 'c', value: 3 }
  }

console.log
  ( ofilter
      ( (v, k) => k !== 'item2'
      , data
      )
      // [ { item1: { key: 'a', value: 1 } }
      // , { item3: { key: 'c', value: 3 } }
      // ]

  , ofilter
      ( x => x.value === 3
      , data
      )
      // [ { item3: { key: 'c', value: 3 } } ]
  )
Run Code Online (Sandbox Code Playgroud)

这两个功能可以通过多种方式实现.我选择附加到Array.prototype.reduce内部,oreduce但你可以轻松地从头开始编写

  • 这是[基准](https://jsperf.com/ed-3-vs-es-2015-vs-es-2016/1),表明您的解决方案是最快的. (3认同)

Wil*_*ilt 8

Array.reduce在允许的键上使用该方法的另一种解决方案:

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = allowed.reduce((obj, key) => { 
  obj[key] = raw[key]; 
  return obj 
}, {})

console.log(filtered);
Run Code Online (Sandbox Code Playgroud)

特别是在较大的源对象(在本例中为原始对象)的情况下,这将是有意义的。不会使用源的所有条目执行迭代,而只会使用要过滤的键,因此更短/更快......

这个小提琴中演示......


但我不得不说我也喜欢这个答案中的解决方案,它使用和:Object.fromEntries Array.filterArray.includes

const object = Object.fromEntries(
  Object.entries(raw).filter(([key, value]) => allowed.includes(key))
);
Run Code Online (Sandbox Code Playgroud)

这个小提琴中演示......


Raj*_*ena 7

这是我最近做的事情:

const dummyObj = Object.assign({}, obj);
delete dummyObj[key];
const target = Object.assign({}, {...dummyObj});
Run Code Online (Sandbox Code Playgroud)

  • 可以用对象传播替换“ Object.assign” (2认同)
  • 嗯。看来你正在混合新旧语法。`Object.assign == ...` 你可以写 `const dummyObj = { ...obj }` 和 `const target = { ...dummyObj }`。另外,后者根本没有必要,因为之后您可以直接使用 dummyObj。 (2认同)

小智 7

现在,您可以使用Object.fromEntries方法(查看浏览器支持)来使其更短,更简单:

const raw = { item1: { prop:'1' }, item2: { prop:'2' }, item3: { prop:'3' } };

const allowed = ['item1', 'item3'];

const filtered = Object.fromEntries(
   Object.entries(raw).filter(
      ([key, val])=>allowed.includes(key)
   )
);
Run Code Online (Sandbox Code Playgroud)

阅读更多有关:Object.fromEntries

  • 这是我现在认为最好的办法。比reduce直观得多。 (3认同)
  • 作为记录。当将 `Object.fromEntries` 与 `Typescript` 结合使用时,请确保在 `tsconfig.json` 中设置了 `"lib": ["ES2019"]` (2认同)

Eva*_*ice 6

捎带ssube 的回答

这是一个可重复使用的版本。

Object.filterByKey = function (obj, predicate) {
  return Object.keys(obj)
    .filter(key => predicate(key))
    .reduce((out, key) => {
      out[key] = obj[key];
      return out;
    }, {});
}
Run Code Online (Sandbox Code Playgroud)

调用它使用

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

var filtered = Object.filterByKey(raw, key => 
  return allowed.includes(key));
});

console.log(filtered);
Run Code Online (Sandbox Code Playgroud)

ES6 箭头函数的美妙之处在于您不必将其allowed作为参数传入。


Ita*_*oam 6

filter可以使用Object.entries()代替而不使用来实现更简单的解决方案Object.keys()

const raw = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const allowed = ['item1', 'item3'];

const filtered = Object.entries(raw).reduce((acc,elm)=>{
  const [k,v] = elm
  if (allowed.includes(k)) {
    acc[k] = v 
  }
  return acc
},{})
Run Code Online (Sandbox Code Playgroud)


ina*_*ova 6

好吧,这种单线呢

    const raw = {
      item1: { key: 'sdfd', value: 'sdfd' },
      item2: { key: 'sdfd', value: 'sdfd' },
      item3: { key: 'sdfd', value: 'sdfd' }
    };

    const filteredKeys = ['item1', 'item3'];

    const filtered = Object.assign({}, ...filteredKeys.map(key=> ({[key]:raw[key]})));
Run Code Online (Sandbox Code Playgroud)

  • 所有答案中最惊人的解决方案。+1 (2认同)

小智 6

简单的方法!去做这个。

const myData = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};
const{item1,item3}=myData
const result =({item1,item3})
Run Code Online (Sandbox Code Playgroud)


Joe*_*afe 5

此处的答案绝对合适,但它们有点慢,因为它们需要遍历对象中每个属性的白名单。对于大型数据集,以下解决方案要快得多,因为它仅循环遍历白名单一次:

const data = {
  allowed1: 'blah',
  allowed2: 'blah blah',
  notAllowed: 'woah',
  superSensitiveInfo: 'whooooah',
  allowed3: 'bleh'
};

const whitelist = ['allowed1', 'allowed2', 'allowed3'];

function sanitize(data, whitelist) {
    return whitelist.reduce(
      (result, key) =>
        data[key] !== undefined
          ? Object.assign(result, { [key]: data[key] })
          : result,
      {}
    );
  }

  sanitize(data, whitelist)
Run Code Online (Sandbox Code Playgroud)


Bou*_*uni 5

你可以这样做:

const base = {
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

const filtered = (
    source => { 
        with(source){ 
            return {item1, item3} 
        } 
    }
)(base);

// one line
const filtered = (source => { with(source){ return {item1, item3} } })(base);
Run Code Online (Sandbox Code Playgroud)

这有效但不是很清楚,而且with不推荐使用该语句(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with)。


wik*_*239 5

我知道这已经有很多答案,并且是一个相当古老的问题。但我刚刚想出了这样一句简洁的话:

JSON.parse(JSON.stringify(raw, ['key', 'value', 'item1', 'item3']))
Run Code Online (Sandbox Code Playgroud)

这将返回另一个仅包含白名单属性的对象。请注意,keyvalue包含在列表中。