假设我有一个对象:

elmo = { 
  color: 'red',
  annoying: true,
  height: 'unknown',
  meta: { one: '1', two: '2'}
};

我想用它的属性子集创建一个新对象。

 // pseudo code
 subset = elmo.slice('color', 'height')

 //=> { color: 'red', height: 'unknown' }

我怎样才能做到呢?


当前回答

我想在这里提到一个非常好的策展:

pick-es2019.js

Object.fromEntries(
  Object.entries(obj)
  .filter(([key]) => ['whitelisted', 'keys'].includes(key))
);

pick-es2017.js

Object.entries(obj)
.filter(([key]) => ['whitelisted', 'keys'].includes(key))
.reduce((obj, [key, val]) => Object.assign(obj, { [key]: val }), {});

pick-es2015.js

Object.keys(obj)
.filter((key) => ['whitelisted', 'keys'].indexOf(key) >= 0)
.reduce((newObj, key) => Object.assign(newObj, { [key]: obj[key] }), {})

omit-es2019.js

Object.fromEntries(
  Object.entries(obj)
  .filter(([key]) => !['blacklisted', 'keys'].includes(key))
);

omit-es2017.js

Object.entries(obj)
.filter(([key]) => !['blacklisted', 'keys'].includes(key))
.reduce((obj, [key, val]) => Object.assign(obj, { [key]: val }), {});

omit-es2015.js

Object.keys(obj)
.filter((key) => ['blacklisted', 'keys'].indexOf(key) < 0)
.reduce((newObj, key) => Object.assign(newObj, { [key]: obj[key] }), {})

其他回答

核心库中没有这样的内置功能,但你可以使用对象解构来实现它…

const {color, height} = sourceObject;
const newObject = {color, height};

你也可以写一个效用函数…

const cloneAndPluck = function(sourceObject, keys) {
    const newObject = {};
    keys.forEach((obj, key) => { newObject[key] = sourceObject[key]; });
    return newObject;
};

const subset = cloneAndPluck(elmo, ["color", "height"]);

像Lodash这样的库也有_.pick()。

如果你正在使用ES6,有一种非常简洁的方法来使用解构来做到这一点。析构允许您轻松地使用扩展添加到对象,但它也允许您以相同的方式创建子集对象。

const object = {
  a: 'a',
  b: 'b',
  c: 'c',
  d: 'd',
}

// Remove "c" and "d" fields from original object:
const {c, d, ...partialObject} = object;
const subset = {c, d};

console.log(partialObject) // => { a: 'a', b: 'b'}
console.log(subset) // => { c: 'c', d: 'd'};

打印稿的解决方案:

function pick<T extends object, U extends keyof T>(
  obj: T,
  paths: Array<U>
): Pick<T, U> {
  const ret = Object.create(null);
  for (const k of paths) {
    ret[k] = obj[k];
  }
  return ret;
}

输入信息甚至允许自动补全:

Credit to definitelytyping for U extends keyof T trick!

打印稿操场

值得注意的是,Zod模式在默认情况下会删除未知属性。如果您已经在使用Zod,那么它很可能适合您的开发过程。

https://github.com/colinhacks/zod

import { z } from "zod";

// muppet schema
const muppet = z.object({
  color: z.string(),
  annoying: z.boolean(),
  height: z.string(),
  meta: z.object({ one: z.string(), two: z.string() }),
});

// TypeScript type if you want it
type TMuppet = z.infer<typeof muppet>;

// elmo example
const elmo: TMuppet = {
  color: "red",
  annoying: true,
  height: "unknown",
  meta: { one: "1", two: "2" },
};

// get a subset of the schema (another schema) if you want
const subset = muppet.pick({ color: true, height: true });

// parsing removes unknown properties by default
subset.parse(elmo); // { color: 'red', height: 'unknown' }

对象数组

const aListOfObjects = [{
    prop1: 50,
    prop2: "Nothing",
    prop3: "hello",
    prop4: "What's up",
  },
  {
    prop1: 88,
    prop2: "Whatever",
    prop3: "world",
    prop4: "You get it",
  },
]

创建一个或多个对象的子集可以通过这种方式解构对象来实现。

const sections = aListOfObjects.map(({prop1, prop2}) => ({prop1, prop2}));