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

在JavaScript对象中仅保留某些属性,javascript,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 } var myObj={ p1:123, p2:321, p100:3434 }

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

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={
    p1:123,
    p2:321,
    p100:3434
}
并且只需要属性p1、p2和p100,如何获得此对象:

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={
    p1:123,
    p2:321,
    p100:3434
}

我知道如何使用蛮力来实现这一点,但我想要一个更优雅的解决方案。

只需重新初始化对象:

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];
    }
}
var prop=['p1','p2','p100'];
for(myObj中的变量k){
if(prop.indexOf(k)<0){
删除myObj[k];
}
}

您可以使用
删除

for (var k in myObj) {
    if (k !== 'p1' && k !== 'p2' && k !== 'p100') {
        delete myObj[k];
    }
}
indexOf
的替代方案:

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

var take = /^p(1|2|100)$/;
for (var k in myObj) {
    take.test(k) || delete myObj[k];
}
到RegExp的数组:

var take = [1, 2, 100];
take = new RegExp('^p(' + take.join('|') + ')$'); // /^p(1|2|100)$/
take.test('p1'); // true
take.test('p3'); // false
在函数中有用:

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

take(myObj, [1, 2, 100]); // { p1: 123, p2: 321, p100: 3434 }
take(myObj, ['p1', 'p2', 'p100']);
// with a middleman :
var idsToTake = [1, 2, 100];
take(myObj, prefix(idsToTake, 'p'));
如果您不喜欢正则表达式:

function take(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;
}

您可以在第一个对象上创建一个视图,这是一种只能看到所需属性的代理。
例如,下面的函数将创建一个视图,允许读写底层对象,只保留choosen属性。
只需删除setter,就可以非常轻松地将其设置为只读。
您可能还希望密封代理对象,以便以后不会对其进行任何修改

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:

结果:

"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) 可以将原始对象保存在隐藏属性/闭包中,以便以后可以更改公开的属性

我想您可以在原型中添加一个新方法:

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']);
if(!('keeponlythesprops'在Object.prototype中)){
Object.prototype.keeponlythesprops=函数(arr){
var-keys=Object.keys(这个);
对于(变量i=0,l=keys.length;i

.

将白名单键的映射传递到IIFE(立即调用的函数表达式);IMO不仅优雅,而且灵活(特别是如果转移到与胡安·门德斯的回答类似的功能中)


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

var o = { a: 1, b: 2 };
delete o.b;
o // { a: 1 }
p // { a: 1 }
o = { a: o.a };
o.c = 3;
o // { a: 1, c: 3 }
p // { a: 1, b: 2 }
对该对象的新引用:

var p = o;
o
p
均指同一对象:

o // { a: 1, b: 2 }
p // { a: 1, b: 2 }
o === p // true
让我们通过
o
更新对象:

var o = { a: 1, b: 2 };
delete o.b;
o // { a: 1 }
p // { a: 1 }
o = { a: o.a };
o.c = 3;
o // { a: 1, c: 3 }
p // { a: 1, b: 2 }
让我们通过
p
更新对象:

p.b = 2;
o // { a: 1, b: 2 }
p // { a: 1, b: 2 }
delete p.a;
o // { a: 1, c: 3 }
p // { b: 2 }
如您所见,
o
p
是同步的


让我们“重新初始化”
o

var o = { a: 1, b: 2 };
delete o.b;
o // { a: 1 }
p // { a: 1 }
o = { a: o.a };
o.c = 3;
o // { a: 1, c: 3 }
p // { a: 1, b: 2 }
o
p
现在指的是不同的对象:

o // { a: 1 }
p // { a: 1, b: 2 }
o === p // false
让我们更新存储在
o
中的对象:

var o = { a: 1, b: 2 };
delete o.b;
o // { a: 1 }
p // { a: 1 }
o = { a: o.a };
o.c = 3;
o // { a: 1, c: 3 }
p // { a: 1, b: 2 }
让我们更新存储在
p
中的对象:

p.b = 2;
o // { a: 1, b: 2 }
p // { a: 1, b: 2 }
delete p.a;
o // { a: 1, c: 3 }
p // { b: 2 }
如您所见,
o
p
不再同步



问题是:您想保持两个变量(
o
p
)同步吗?如果是这样,则的第二个代码块是正确的,否则,请选择第一个代码块。

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

最“优雅”的解决方案可能只是使用下划线.js

_.pick(myObj, 'p1', 'p2', 'p100')
有一个名为的函数,它执行您所描述的操作。我知道包含一个库并不理想,但您也可以在使用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')

您可以编写自己的
实现。选择
,并根据需要使用它

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

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: 您想要一个浅拷贝(带有对向量值的引用)

案例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 }​​​​​
免责声明:


这只是一个不处理属性中的
日期
设置
映射
函数
值的示例。要处理所有这些情况(以及许多其他情况),它需要一个非常复杂的函数,对原型和所有这些东西进行检查。在这一点上,考虑重用其他开发人员的工作,使用任何能做到这一点的库。Lodash?

我为我有一个包含对象的数组的情况制定了这个简短的解决方案

>考虑下面的数组?

arr=[{“a1”:“a1”,“b1”:“b1”},{“a1”:“Z1”,“b1”:“X1”}];

控制台日志(arr)您可以使用以下方法:

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


这是我在。

@JuanMendes上学到的。它不会克隆它。但是你仍然没有用第二个代码块启动的对象。与第一个代码块不同,第二个代码块有效。实际上,如果另一个变量引用了
myObj
?@VisioN对第一个对象的任何其他引用呢?属性的数量不是问题@user1032531,请关注这句话:“如果不需要保留对原始对象的引用”。给我一分钟,我会发布一个答案给你解释。在我看来,这是蛮力,他不想要that@tewathia请详细说明“暴力”。根据OP的问题,这是最具动态性的方法。好吧,你正在检查对象的所有属性(我同意这确实是在不克隆对象的情况下获得所需对象的最佳方法),我相信这就是他所说的“蛮力”为什么要使用两个嵌套循环和
indexOf
?@GeorgeJempty你很挑剔;)顺便问一下,跨浏览器兼容吗:我认为如果不使用暴力(或克隆o