如何获取javascript对象属性的子集

2020/09/27 11:01 · javascript ·  · 0评论

说我有一个对象:

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

我想用其属性的子集制作一个新对象。

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

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

我该如何实现?

使用对象分解和属性速记

const object = { a: 5, b: 6, c: 7  };
const picked = (({ a, c }) => ({ a, c }))(object);

console.log(picked); // { a: 5, c: 7 }

来自Philipp Kewisch:

这实际上只是一个即时调用的匿名函数。所有这些都可以在MDN 的“ 解构分配”页面上找到这是扩展形式

let unwrap = ({a, c}) => ({a, c});

let unwrap2 = function({a, c}) { return { a, c }; };

let picked = unwrap({ a: 5, b: 6, c: 7 });

let picked2 = unwrap2({a: 5, b: 6, c: 7})

console.log(picked)
console.log(picked2)

我建议看一看Lodash它具有很多出色的实用程序功能。

例如pick(),正是您想要的:

var subset = _.pick(elmo, ['color', 'height']);

小提琴

如果您使用的是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'};

虽然有点冗长,但是您可以使用Array.prototype.reduce完成 2年前其他人推荐的下划线/破折号

var subset = ['color', 'height'].reduce(function(o, k) { o[k] = elmo[k]; return o; }, {});

这种方法从另一方面解决了问题:不要采用对象并将属性名称传递给它来进行提取,而是采用属性名称数组并将其简化为新对象。

尽管在最简单的情况下它比较冗长,但这里的回调非常方便,因为您可以轻松满足一些常见要求,例如,在新对象上将'color'属性更改为'colour',展平数组等。从一个服务/库接收对象并构建其他地方需要的新对象时需要做的事情。下划线/破折号是出色的,实现良好的库,这是我首选的减少供应商依赖性的方法,当我的子集构建逻辑变得更复杂时,这是更简单,更一致的方法。

编辑:es7版本相同:

const subset = ['color', 'height'].reduce((a, e) => (a[e] = elmo[e], a), {});

编辑:也是一个不错的例子。有一个“ pick”功能返回另一个功能。

const pick = (...props) => o => props.reduce((a, e) => ({ ...a, [e]: o[e] }), {});

上面的方法与其他方法非常接近,除了它使您可以动态构建“选择器”。例如

pick('color', 'height')(elmo);

这种方法特别整洁的是,您可以轻松地将所选的“小贴士”传递给具有功能的任何内容,例如Array#map

[elmo, grover, bigBird].map(pick('color', 'height'));
// [
//   { color: 'red', height: 'short' },
//   { color: 'blue', height: 'medium' },
//   { color: 'yellow', height: 'tall' },
// ]

ES6解构

分解语法允许使用函数参数或变量来分解和重​​组对象。

限制是键列表是预定义的,正如问题所提到的,它们不能以字符串形式列出。如果键是非字母数字(例如),则解构将变得更加复杂foo_bar

缺点是,这需要重复键列表,如果列表很长,则会导致冗长的代码。由于在这种情况下解构重复对象的文字语法,因此可以按原样复制和粘贴列表。

好处是它是ES6固有的高性能解决方案。

国际教育展

let subset = (({ foo, bar }) => ({ foo, bar }))(obj); // dupe ({ foo, bar })

临时变量

let { foo, bar } = obj;
let subset = { foo, bar }; // dupe { foo, bar }

字符串列表

根据问题的要求,选择的键的任意列表由字符串组成。这样就可以不预定义它们,而使用包含键名的变量,例如pick(obj, 'foo', someKey, ...moreKeys)

每个JS版本的单线都变得更短。

ES5

var subset = Object.keys(obj)
.filter(function (key) { 
  return ['foo', 'bar'].indexOf(key) >= 0;
})
.reduce(function (obj2, key) {
  obj2[key] = obj[key];
  return obj2;
}, {});

ES6

let subset = Object.keys(obj)
.filter(key => ['foo', 'bar'].indexOf(key) >= 0)
.reduce((obj2, key) => Object.assign(obj2, { [key]: obj[key] }), {});

或使用逗号运算符:

let subset = Object.keys(obj)
.filter(key => ['foo', 'bar'].indexOf(key) >= 0)
.reduce((obj2, key) => (obj2[key] = obj[key], obj2), {});

ES2019

ECMAScript 2017具有Object.entriesArray.prototype.includes,ECMAScript 2019具有Object.fromEntries,可以在需要时进行填充,使任务更轻松:

let subset = Object.fromEntries(
  Object.entries(obj)
  .filter(([key]) => ['foo', 'bar'].includes(key))
)

可以将单行代码重写为类似于Lodash的pick辅助函数,或者omit将键列表通过参数传递:

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

let subset = pick({ foo: 1, qux: 2 }, 'foo', 'bar'); // { foo: 1 }

关于遗失钥匙的注意事项

解构和传统的类似Lodash的pick函数之间的主要区别在于,解构包括undefined子集中不存在带有值的选取键

(({ foo, bar }) => ({ foo, bar }))({ foo: 1 }) // { foo: 1, bar: undefined }

此行为可能是或不希望的。不能为解构语法而更改它。

pick可以通过迭代选择的键的列表来将While 更改为包括丢失的键:

let inclusivePick = (obj, ...keys) => Object.fromEntries(
  keys.map(key => [key, obj[key]])
);

let subset = inclusivePick({ foo: 1, qux: 2 }, 'foo', 'bar'); // { foo: 1, bar: undefined }

核心库中没有内置的东西,但是您可以使用对象分解来实现...

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

我添加此答案是因为没有使用任何答案Comma operator

destructuring assignment,操作符非常简单

const object = { a: 5, b: 6, c: 7  };
const picked = ({a,c} = object, {a,c})

console.log(picked);

另一种解决方案:

var subset = {
   color: elmo.color,
   height: elmo.height 
}

对于我来说,这似乎比到目前为止的任何答案都更具可读性,但是也许就是我!

您也可以使用Lodash

var subset = _.pick(elmo ,'color', 'height');

作为补充,假设您有一个数组“ elmo”:

elmos = [{ 
      color: 'red',
      annoying: true,
      height: 'unknown',
      meta: { one: '1', two: '2'}
    },{ 
      color: 'blue',
      annoying: true,
      height: 'known',
      meta: { one: '1', two: '2'}
    },{ 
      color: 'yellow',
      annoying: false,
      height: 'unknown',
      meta: { one: '1', two: '2'}
    }
];

如果您希望使用lodash进行相同的操作,则只需:

var subsets = _.map(elmos, function(elm) { return _.pick(elm, 'color', 'height'); });

TypeScript解决方案:

export function pick<T extends object, U extends keyof T>(obj: T, paths: Array<U>) {
    return paths.reduce((o, k) => {
        o[k] = obj[k];
        return o;
    }, Object.create(null));
}

输入信息甚至可以自动完成:

信贷DefinitelyTypedU extends keyof T把戏!

如本问题所述,在JavaScript中将其分解为动态命名的变量是不可能的

动态设置键,可以使用reduce函数,而无需更改对象,如下所示:

const getSubset = (obj, ...keys) => keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});

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

const subset = getSubset(elmo, 'color', 'annoying')
console.log(subset)

应该注意的是,尽管不是更新单个克隆,但每次迭代都在创建一个新对象。– mpen

以下是使用带有单个克隆的reduce的版本(更新传递给reduce的初始值)。

const getSubset = (obj, ...keys) => keys.reduce((acc, curr) => {
  acc[curr] = obj[curr]
  return acc
}, {})

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

const subset = getSubset(elmo, 'annoying', 'height', 'meta')
console.log(subset)

动态解决方案

['color', 'height'].reduce((a,b) => (a[b]=elmo[b],a), {})

picklodash库的使用方法(如果已在使用)。

var obj = { 'a': 1, 'b': '2', 'c': 3 };

_.pick(object, ['a', 'c']);

// => { 'a': 1, 'c': 3 }

https://lodash.com/docs/4.17.10#pick

我想提一提的是这里很不错的策展:

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

换一种方式...

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

var subset = [elmo].map(x => ({
  color: x.color,
  height: x.height
}))[0]

您可以将此函数与Objects =)数组一起使用

怎么样:

function sliceObj(obj) {
  var o = {}
    , keys = [].slice.call(arguments, 1);
  for (var i=0; i<keys.length; i++) {
    if (keys[i] in obj) o[keys[i]] = obj[keys[i]];
  }
  return o;
}

var subset = sliceObj(elmo, 'color', 'height');

这在Chrome控制台中对我有效。有什么问题吗?

var { color, height } = elmo
var subelmo = { color, height }
console.log(subelmo) // {color: "red", height: "unknown"}
  1. 将参数转换为数组

  2. 用于Array.forEach()挑选物业

    Object.prototype.pick = function(...args) {
       var obj = {};
       args.forEach(k => obj[k] = this[k])
       return obj
    }
    var a = {0:"a",1:"b",2:"c"}
    var b = a.pick('1','2')  //output will be {1: "b", 2: "c"}
    

具有动态属性的销毁分配

此解决方案不仅适用于您的特定示例,而且更适用于:

const subset2 = (x, y) => ({[x]:a, [y]:b}) => ({[x]:a, [y]:b});

const subset3 = (x, y, z) => ({[x]:a, [y]:b, [z]:c}) => ({[x]:a, [y]:b, [z]:c});

// const subset4...etc.


const o = {a:1, b:2, c:3, d:4, e:5};


const pickBD = subset2("b", "d");
const pickACE = subset3("a", "c", "e");


console.log(
  pickBD(o), // {b:2, d:4}
  pickACE(o) // {a:1, c:3, e:5}
);

您可以轻松定义subset4等以考虑更多属性。

好旧的Array.prototype.reduce

const selectable = {a: null, b: null};
const v = {a: true, b: 'yes', c: 4};

const r = Object.keys(selectable).reduce((a, b) => {
  return (a[b] = v[b]), a;
}, {});

console.log(r);

这个答案还使用了神奇的逗号运算符,也:https :
//developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator

如果您真的想花哨的话,这会更紧凑:

const r = Object.keys(selectable).reduce((a, b) => (a[b] = v[b], a), {});

将它们放到一个可重用的函数中:

const getSelectable = function (selectable, original) {
  return Object.keys(selectable).reduce((a, b) => (a[b] = original[b], a), {})
};

const r = getSelectable(selectable, v);
console.log(r);
function splice()
{
    var ret = new Object();

    for(i = 1; i < arguments.length; i++)
        ret[arguments[i]] = arguments[0][arguments[i]];

    return ret;
}

var answer = splice(elmo, "color", "height");

尝试

const elmo={color:"red",annoying:!0,height:"unknown",meta:{one:"1",two:"2"}};

const {color, height} = elmo; newObject = ({color, height});

console.log(newObject); //{ color: 'red', height: 'unknown' }

将2美分加到Ivan Nosov的答案中:

以我为例,我需要从对象中“切出”许多键,因此它变得非常丑陋,而且不是一种动态解决方案:

const object = { a: 5, b: 6, c: 7, d: 8, aa: 5, bb: 6, cc: 7, dd: 8, aaa: 5, bbb: 6, ccc: 7, ddd: 8, ab: 5, bc: 6, cd: 7, de: 8  };
const picked = (({ a, aa, aaa, ab, c, cc, ccc, cd }) => ({ a, aa, aaa, ab, c, cc, ccc, cd }))(object);

console.log(picked);

所以这是一个使用eval的动态解决方案:

const slice = (k, o) => eval(`(${k} => ${k})(o)`);


const object    = { a: 5, b: 6, c: 7, d: 8, aa: 5, bb: 6, cc: 7, dd: 8, aaa: 5, bbb: 6, ccc: 7, ddd: 8, ab: 5, bc: 6, cd: 7, de: 8  };
const sliceKeys = '({ a, aa, aaa, ab, c, cc, ccc, cd })';

console.log( slice(sliceKeys, object) );

我遇到了同样的问题,可以通过使用以下库轻松解决它:

object.pick

https://www.npmjs.com/package/object.pick

pick({a: 'a', b: 'b', c: 'c'}, ['a', 'b'])
//=> {a: 'a', b: 'b'}

对象省略

https://www.npmjs.com/package/object.omit

omit({a: 'a', b: 'b', c: 'c'}, ['a', 'c'])
//=> { b: 'b' }

注意:尽管最初提出的问题是针对javascript的,但可以通过以下解决方案完成jQuery

您可以扩展jquery,如果您想获得一个切片的示例代码:

jQuery.extend({
  sliceMe: function(obj, str) {
      var returnJsonObj = null;
    $.each( obj, function(name, value){
        alert("name: "+name+", value: "+value);
        if(name==str){
            returnJsonObj = JSON.stringify("{"+name+":"+value+"}");
        }

    });
      return returnJsonObj;
  }
});

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


var temp = $.sliceMe(elmo,"color");
alert(JSON.stringify(temp));

这是相同的小提琴:http : //jsfiddle.net/w633z/

本文地址:http://javascript.askforanswer.com/ruhehuoqujavascriptduixiangshuxingdeziji.html
文章标签:
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!