在ES6中按键过滤对象属性

时间:2016-08-03 18:02:09

标签: filter ecmascript-6

假设我有一个对象:

{
  item1: { key: 'sdfd', value:'sdfd' },
  item2: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
}

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

 {
    item1: { key: 'sdfd', value:'sdfd' },
    item3: { key: 'sdfd', value:'sdfd' }
 }

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

29 个答案:

答案 0 :(得分:295)

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



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);




这使用:

  1. Object.keys列出raw中所有属性(原始数据),然后
  2. Array.prototype.filter使用选择允许列表中存在的键
    1. Array.prototype.includes确保他们在场
  3. Array.prototype.reduce构建一个只包含允许属性的新对象。
  4. 这将使用允许的属性进行浅层复制(但不会自行复制属性)。

    你也可以使用the object spread operator创建一系列对象而不会改变它们(感谢rjerue for mentioning this):

    
    
    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);
    
    
    

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

    
    
    includes
    
    
    

    我包括这个例子来展示一个基于突变的解决方案,但我不建议使用它。

答案 1 :(得分:54)

如果您对使用ES6语法没问题,我发现最简洁的方法是执行此操作,如herehere所示:

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

const { item2, ...newData } = data;

现在,newData包含:

{
  item1: { key: 'sdfd', value:'sdfd' },
  item3: { key: 'sdfd', value:'sdfd' }
};

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

const key = 'item2';
const { [key]: _, ...newData } = data;

在后一种情况下,[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, ...

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

答案 2 :(得分:31)

您可以找到最简洁的方法是使用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)

答案 3 :(得分:14)

之前没有说过什么,而是将一些答案与一般的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);

答案 4 :(得分:11)

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

我正在玩" 解构"功能:



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);




答案 5 :(得分:6)

您可以添加通用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
    )

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

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 } } ]
  )

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

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 } } ]
  )

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

答案 6 :(得分:5)

使用“新” 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);

Demonstration in this Fiddle...


但是我喜欢this answer here中使用Object.fromEntries Array.filterArray.includes的解决方案:

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

Demonstration in this Fiddle...

答案 7 :(得分:4)

这就是我最近的做法:

const dummyObj = Object.assign({}, obj);
delete dummyObj[key];
const target = Object.assign({}, {...dummyObj});

答案 8 :(得分:3)

好吧,这种单线呢

    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]})));

答案 9 :(得分:3)

捎带ssube's answeranswer

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

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

要调用它

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);

关于ES6箭头功能的美妙之处在于,您不必将allowed作为参数传递。

答案 10 :(得分:2)

这里的答案绝对合适,但它们有点慢,因为它们需要通过白名单循环访问对象中的每个属性。对于大型数据集,下面的解决方案要快得多,因为它只会循环通过白名单一次:

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)

答案 11 :(得分:2)

上述许多解决方案对Array.prototype.includes中的每个键重复调用raw,这将使解决方案O(n·m)(其中n是对象中的键数,m是允许列表的长度)。

这可以通过使用允许的 Set 来避免,但是迭代 allowed 键并将它们复制到初始为空的对象中会得到非常简单、可读的代码,即 O(m):

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

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

const filtered = {};
for (const key of allowed) {
  if (key in raw) filtered[key] = raw[key];
}

console.log(filtered);

如果您想避免复制继承的属性,也可以使用 raw.hasOwnProperty(key) 代替 key in raw

答案 12 :(得分:2)

我很惊讶没有人提出这个建议。非常干净,而且非常明确地表明您要保留哪些密钥。

const unfilteredObj = {a: ..., b:..., c:..., x:..., y:...}

const filterObject = ({a,b,c}) => ({a,b,c})
const filteredObject = filterObject(unfilteredObject)

或者如果您想要一个肮脏的内胆:

const unfilteredObj = {a: ..., b:..., c:..., x:..., y:...}

const filteredObject = (({a,b,c})=>({a,b,c}))(unfilteredObject);

答案 13 :(得分:2)

const filteredObject = Object.fromEntries(Object.entries(originalObject).filter(([key, value]) => key !== uuid))

答案 14 :(得分:2)

可以使用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
},{})

答案 15 :(得分:2)

您可以执行以下操作:

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);

这有效,但不是很清楚,另外不建议使用with语句(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with)。

答案 16 :(得分:1)

您可以删除对象上的特殊键

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

// Example 1
var key = "item2";
delete items[key]; 

// Example 2
delete items["item2"];

// Example 3
delete items.item2;

答案 17 :(得分:1)

简单方法!为此。

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})

答案 18 :(得分:1)

另一种简便方法

function filterByKey(v,keys){
  const newObj ={};
  keys.forEach(key=>{v[key]?newObj[key]=v[key]:''});
  return newObj;
}

//given
let obj ={ foo: "bar", baz: 42,baz2:"blabla" , "spider":"man", monkey:true};

//when
let outObj =filterByKey(obj,["bar","baz2","monkey"]);

//then 
console.log(outObj);
  //{
  //  "baz2": "blabla",
  //  "monkey": true
  //}

答案 19 :(得分:1)

我知道这已经有很多答案了 是一个相当老的问题。但是我只是想出了这种简洁的单线纸:

JSON.parse(JSON.stringify(raw, ['key', 'value', 'item1', 'item3']))

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

答案 20 :(得分:0)

好的,:这是怎么回事:

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

function filteredObject(obj, filter) {
  if(!Array.isArray(filter)) {
   filter = [filter.toString()];
  }
  const newObj = {};
  for(i in obj) {
    if(!filter.includes(i)) {
      newObj[i] = obj[i];
    }
  }
  return newObj;
}

并将其称为:

filteredObject(myData, ['item2']); //{item1: { key: 'sdfd', value:'sdfd' }, item3: { key: 'sdfd', value:'sdfd' }}

答案 21 :(得分:0)

在循环期间,遇到某些属性/键时不返回任何内容,然后继续进行其余操作:

const loop = product =>
Object.keys(product).map(key => {
    if (key === "_id" || key === "__v") {
        return; 
    }
    return (
        <ul className="list-group">
            <li>
                {product[key]}
                <span>
                    {key}
                </span>
            </li>
        </ul>
    );
});

答案 22 :(得分:0)

您现在可以使用 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)));

详细了解以下内容:Object.fromEntries

答案 23 :(得分:0)

此函数将根据键列表过滤对象,它比以前的答案更有效,因为在调用reduce之前不必使用Array.filter。因此它的O(n)不同于O(n +已过滤)

function filterObjectByKeys (object, keys) {
  return Object.keys(object).reduce((accum, key) => {
    if (keys.includes(key)) {
      return { ...accum, [key]: object[key] }
    } else {
      return accum
    }
  }, {})
}

答案 24 :(得分:0)

另一种方法是将Array.prototype.forEach()用作

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

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

var finalObj = {};
allowed.forEach(allowedVal => {
  if (raw[allowedVal])
    finalObj[allowedVal] = raw[allowedVal]
})
console.log(finalObj)

它仅包含原始数据中可用的那些键的值,从而防止添加任何垃圾数据。

答案 25 :(得分:0)

那是我的解决办法:

const filterObject = (obj, condition) => {
    const filteredObj = {};
    Object.keys(obj).map(key => {
      if (condition(key)) {
        dataFiltered[key] = obj[key];
      }
    });
  return filteredObj;
}

答案 26 :(得分:0)

以下方法将对象和所有属性过滤掉。

function removeObjectKeys(obj, ...keysToRemove) {
  let mObject = { ...obj }
  for (let key of keysToRemove) {
    const { [String(key)]: _, ...rest } = mObject
    mObject = { ...rest }
  }
  return mObject
}
    
const obj = { 123: "hello", 345: "world", 567: "and kitty" };
const filtered = removeObjectKeys(obj, 123);
console.log(filtered);

const twoFiltered = removeObjectKeys(obj, 345, 567);
console.log(twoFiltered);

答案 27 :(得分:0)

使用 PropPick


pick('item1 item3', obj);
// {
//   item1: { key: 'sdfd', value:'sdfd' },
//   item3: { key: 'sdfd', value:'sdfd' }
// }

答案 28 :(得分:0)

有很多方法可以实现这一目标。 accepted answer使用Keys-Filter-Reduce方法,这种方法效果不是最好的。

相反,使用for...in循环来循环访问对象的键,或循环通过允许的键,然后组成一个新对象的性能提高约50%一个

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

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

function keysReduce (obj, keys) {
  return keys.reduce((acc, key) => {
    if(obj[key] !== undefined) {
      acc[key] = obj[key];
    }
    return acc;
  }, {});
};

function forInCompose (obj, keys) {
  const returnObj = {};
  for (const key in obj) {
    if(keys.includes(key)) {
      returnObj[key] = obj[key]
    }
  };
  return returnObj;
};

keysReduce(obj, keys);   // Faster if the list of allowed keys are short
forInCompose(obj, keys); // Faster if the number of object properties are low

一个。有关简单用例的基准,请参阅jsPerf。结果将根据浏览器而有所不同。