仅保留JavaScript对象中的某些属性

时间:2014-03-05 15:59:15

标签: javascript

我有一个对象。我想通过删除除某些特定属性之外的所有属性来修改对象(而不是克隆它)。例如,如果我开始使用这个对象:

var myObj={
    p1:123,
    p2:321,
    p3:{p3_1:1231,p3_2:342},
    p4:'23423',
    //....
    p99:{p99_1:'sadf',p99_2:234},
    p100:3434
}

并且只想要属性p1,p2和p100,我该如何获得这个对象:

var myObj={
    p1:123,
    p2:321,
    p100:3434
}

我理解如何用蛮力做到这一点,但想要更优雅的解决方案。

12 个答案:

答案 0 :(得分:6)

重新初始化对象:

myObj = {
    p1:   myObj.p1,
    p2:   myObj.p2,
    p100: myObj.p100
};

另一种方法是删除某些效果较差的属性:

var prop = ['p1', 'p2', 'p100'];
for (var k in myObj) {
    if (prop.indexOf(k) < 0) {
        delete myObj[k];
    }
}

答案 1 :(得分:6)

这是谷歌搜索'js仅保留某些键'时的第一次点击,因此可能值得更新。

最“优雅”的解决方案可能就是使用underscore.js

_.pick(myObj, 'p1', 'p2', 'p100')

答案 2 :(得分:3)

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

function keepProps(obj, keep) {
    for (var prop in obj) {
        if (keep.indexOf( prop ) == -1) {
            delete obj[prop];
        }             
    }
}

keepProps(myObj, ['a', 'b']);
console.log(myObj);

http://jsfiddle.net/mendesjuan/d8Sp3/2/

答案 3 :(得分:3)

您可以使用delete

for (var k in myObj) {
    if (k !== 'p1' && k !== 'p2' && k !== 'p100') {
        delete myObj[k];
    }
}

indexOf的替代方案:

var keep = /^p(1|2|100)$/;
for (var k in myObj) {
    if (!keep.test(k)) {
        delete myObj[k];
    }
}

更短:

var keep = /^p(1|2|100)$/;
for (var k in myObj) {
    keep.test(k) || delete myObj[k];
}

RegExp数组:

var keep = [1, 2, 100];
keep = new RegExp('^p(' + keep.join('|') + ')$'); // /^p(1|2|100)$/
keep.test('p1'); // true
keep.test('p3'); // false

对函数有用:

function keep(o, ids) {
    var keep = new RegExp('^p(' + ids.join('|') + ')$');
    for (var k in o) keep.test(k) || delete o[k];
    return o;
}

用法:

keep(myObj, [1, 2, 100]); // { p1: 123, p2: 321, p100: 3434 }

您不喜欢正则表达式,但仍需要防弹解决方案:

function keep(o, keys) {
    for (var k in o) contains(keys, k) || delete o[k];
    return o;
}

function contains(array, value) {
    var i = -1, l = array.length;
    while (++i < l) if (array[i] === value) return true;
    return false;
}

function prefix(array, prefix) {
    var i = -1, l = array.length, output = [];
    while (++i < l) output.push(prefix + array[i]);
    return output;
}

用法:

keep(myObj, ['p1', 'p2', 'p100']);
// with a middleman :
var idsToKeep = [1, 2, 100];
keep(myObj, prefix(idsToKeep, 'p'));

好吧,我可以无限地继续这样做,但现在是时候吃了。

答案 4 :(得分:3)

Lodash有一个名为pick的函数可以完成您所描述的内容。我知道包含一个库并不理想,但你也可以在使用bundle等时选择函数。

var myObj={
    p1:123,
    p2:321,
    p3:{p3_1:1231,p3_2:342},
    p4:'23423',
    //....
    p99:{p99_1:'sadf',p99_2:234},
    p100:3434
}

var newObj = _.pick(myObj, 'p1', 'p2', 'p100')

答案 5 :(得分:1)

存储在名为o的变量中的对象:

var o = { a: 1, b: 2 };

对此对象的新引用:

var p = o;

op都指向同一个对象:

o // { a: 1, b: 2 }
p // { a: 1, b: 2 }
o === p // true

让我们通过o更新对象:

delete o.b;
o // { a: 1 }
p // { a: 1 }

让我们通过p更新对象:

p.b = 2;
o // { a: 1, b: 2 }
p // { a: 1, b: 2 }

如您所见,op是同步的。


让我们“重新初始化”o

o = { a: o.a };

op现在引用不同的对象:

o // { a: 1 }
p // { a: 1, b: 2 }
o === p // false

让我们更新o中存储的对象:

o.c = 3;
o // { a: 1, c: 3 }
p // { a: 1, b: 2 }

让我们更新p中存储的对象:

delete p.a;
o // { a: 1, c: 3 }
p // { b: 2 }

如您所见,op不再同步。


问题是:您是否要同时保持两个变量(op)?如果是,则VisioN's answer的第二个代码块是正确的,否则,选择第一个代码块。

答案 6 :(得分:1)

您可以使用这种方法:

let result = (({ p1, p2, p100 }) => ({ p1, p2, p100 }))(myObj);

我在 https://stackoverflow.com/a/25554551/470749 学到的。

答案 7 :(得分:0)

您可以在第一个对象上创建一个视图,某种代理只能保持所需的属性 例如,以下函数将创建一个允许读取和写入底层对象的视图,仅保留选择的属性 只需移除设定器,即可轻松实现只读 您可能还想密封代理对象,以便以后不再对其进行修改。

function createView(obj, propList) {
    var proxy = {};     
    for (var propIndex in propList) {    
         var prop=propList[propIndex];
         Object.defineProperty(proxy, prop, 
                {  enumerable : true , 
                   get : getter.bind(obj,prop), 
                   set : setter.bind(obj,prop)   } );

    }    
  return proxy;
}

function getter(prop) { return this[prop] ; }

function setter(prop, value) { return this[prop] = value ; }

使用的一个例子是:

var myObj={
    p1:123,
    p2:321,
    p3:{p3_1:1231,p3_2:342},
    p4:'23423',
    p99:{p99_1:'sadf',p99_2:234},
    p100:3434
};

var objView = createView(myObj, ['p1', 'p2', 'p100']);

这里,objView'反映'myObj的所需属性。 你可以看看我在这里制作的小jsbin:

http://jsbin.com/munudewa/1/edit?js,console

结果:

"on objView, p1:123 p2:321 p100:3434 and p4 (not in view) is : undefined"
"modifiying, on the view,  p1 to 1000 and p2 to hello "
"on objView, p1:1000 p2:hello p100:3434 and p4 (not in view) is : undefined"
"modifiying, on the viewed object,  p1 to 200 and p2 to bye "
"on objView, p1:200 p2:bye p100:3434 and p4 (not in view) is : undefined"

注意:
1)您可以通过视图覆盖对象,只保留所需的属性 2)您可以将原始对象保存在隐藏属性/闭包中,以便稍后更改您公开的属性。

答案 8 :(得分:0)

我想你可以为原型添加一个新方法:

if (!('keepOnlyTheseProps' in Object.prototype)) {
  Object.prototype.keepOnlyTheseProps = function (arr) {
    var keys = Object.keys(this);
    for (var i = 0, l = keys.length; i < l; i++) {
      if (arr.indexOf(keys[i]) < 0) delete this[keys[i]];
    }
  }
}

myObj.keepOnlyTheseProps(['p1', 'p2', 'p100']);

Fiddle

答案 9 :(得分:0)

将列入白名单的密钥映射到IIFE(立即调用的函数表达式);不仅仅是优雅而且灵活的IMO(特别是如果转移到与Juan Mendes的回答不同的功能)

var myObj={
    p1:123,
    p2:321,
    p3:{p3_1:1231,p3_2:342},
    p4:'23423',
    //....
    p99:{p99_1:'sadf',p99_2:234},
    p100:3434
}

var myObj = (function(origObj, whiteListMap) {
    for (var prop in origObj) {
        if (!whiteListMap[prop]) {
            delete origObj[prop];
        }
    }
    return myObj;
})(myObj, {'p1': 1, 'p2': 1, 'p100': 1});

console.log(JSON.stringify(myObj)); //{"p1":123,"p2":321,"p100":3434}

答案 10 :(得分:0)

您可以编写自己的_.pick实施代码,并根据您的需要使用它。

将以下代码段作为以下情况的基础:

const myObj={
    p1:123,
    p2:321,
    p3:{p3_1:1231,p3_2:342},
    p4:'23423',
    //....
    p99:{p99_1:'sadf',p99_2:234},
    p100:3434
}
let properties= ['p1','p2', 'p3', 'p100'];

案例1:

您需要浅层副本(引用向量值)

const myNewObj = properties.reduce((newObj,property)=>{newObj[property] = myObj[property]; return newObj}, {})
// if we modify the original vector value of 'p3' in `myObj` we will modify the copy as well:

myObj.p3.p3_1 = 99999999999;

console.log(myNewObj); // { p1: 123,​​​​​​​​​​  p2: 321,​​​​​​​​​​  p3: { p3_1: 99999999999, p3_2: 42 },​​​​​​​​​​  p100: 3434 }​​​​​

案例2:

您需要深层复制(失去对矢量值的引用)

您可以使用JSON实用程序。

const myNewObj2 = properties.reduce((newObj,property)=>{newObj[property] = JSON.parse(JSON.stringify(myObj[property])); return newObj},{})

// no matter how hard you modify the original object, you will create a new independent object
myObj.p3.p3_1 = 99999999999;

console.log(myNewObj2) // { p1: 123, p2: 321, p3: { p3_1: 1231, p3_2: 342 }, p100: 3434 }​​​​​

使用函数

重用案例2

你可以实现一个reducer在不同的场景中使用它,比如这个:

function reduceSelectedProps(origin, properties){
  return (newObj,property)=>{
    newObj[property] = JSON.parse(JSON.stringify(origin[property]));
     return newObj
  }
}

所以你可以更优雅地重复使用它:

const myNewObj3 = properties.reduce(reduceSelectedProps(myObj, properties),{});
// no matter how hard you modify the original object, you will create a new independent object
myObj.p3.p3_1 = 99999999999;

console.log(myNewObj3) // { p1: 123, p2: 321, p3: { p3_1: 1231, p3_2: 342 }, p100: 3434 }​​​​​

<强>免责声明:

这只是一个不处理属性中DateSetMapfunction值的示例。为了处理所有这些情况(以及许多其他情况),它需要一个非常复杂的功能,检查原型和所有这些东西。此时,请考虑重复使用任何可以执行此操作的库的其他开发人员的工作。 Lodash?

答案 11 :(得分:0)

对于有对象数组的情况,我做了简短的解决方案。

所以考虑下面的数组吗?

arr=[{"a1":"A1","b1":"B1"},{"a1":"Z1","b1":"X1"}];
console.log(arr);

我只希望保留所有对象的“ b1”属性。

您可以使用map()并将其删除,如下所示:

arr=[{"a1":"A1","b1":"B1"},{"a1":"Z1","b1":"X1"}];
arr=arr.map(function(d){
        delete d["a1"];
        return d;

    });
console.log(arr);

结果是一个包含对象但只有“ b1”属性的数组。