在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