How to use object rest operator to omit properties dynamically - javascript

I'm using the ES7 Object Rest Operator to Omit Properties from an object, but I'd like to make it more flexible so that I can dynamically provide the list of properties to exclude.
const myObject = {
a: 1,
b: 2,
c: 3
};
const { a, ...noA } = myObject;
console.log(noA); // => { b: 2, c: 3 }
Is there a way to make this more dynamic such that I can call a function and provide an array of properties to exclude instead of the hardcoded approach taken with properties a and b in this example?
Ideally I could have something along these lines -- but this syntax is invalid:
function omitProperties(myObj, fieldsToExclude) {
const { ...fieldsToExclude, ...noA } = myObj;
console.log(noA); // => { b: 2, c: 3 }
}
omitProperties(myObject, [`a`]);

You can consider _.omit.
You can also consider the following:
let omitProperties = (props, exclude) => {
let result = { ...props };
for (let propName of exclude) delete result[propName];
return result;
};
There's quite a bit of discussion about this same issue here.

Related

Implementing a set that treats object equality on value not reference

I want to be able to implement a Set in javascript that allows me to do something like this:
const s = Set([[1,2,3], [1,2,3], 1, 2, 1]);
s.add([1,2,3]);
console.log(s);
// {[1,2,3], 1, 2}
Of course, since the === operator is used on the set, any object will not equal itself unless a reference to the same object is passed, and so instead of the above we would currently get:
Set(5) { [ 1, 2, 3 ], [ 1, 2, 3 ], 1, 2, [ 1, 2, 3 ] }
Does the following seem like a good way to implement this? What might I be missing or can improve on?
class MySet extends Set {
constructor(...args) {
super();
for (const elem of args) {
if (!this.has(elem)) super.add(elem);
}
}
has(elem) {
if (typeof elem !== 'object') return super.has(elem);
for (const member of this) {
if (typeof member !== 'object') continue;
if (JSON.stringify(member) === JSON.stringify(elem))
return true;
}
return false;
}
add(elem) {
return (this.has(elem)) ? this : super.add(elem);
}
delete(elem) {
if (typeof elem !== 'object') return super.delete(elem);
for (const member of this) {
if (typeof member !== 'object') continue;
if (JSON.stringify(member) === JSON.stringify(elem))
return super.delete(member);
}
return false;
}
}
Assuming the provided objects don't contain values that cannot be stringified to JSON (function, undefined, symbol, etc.) You can use JSON.stringify().
One problem you might encounter is that stringifying { a: 1, b: 2 } doesn't produce the same result as { b: 2, a: 1 }. A fairly easy way to solve this would be to stringify the object and make sure the resulting JSON has properties placed in alphabetical order.
For this we can look to the answer provided in sort object properties and JSON.stringify.
I also think you are over complicating things by only stringifying values if they are an object. Instead you could just stringfy everything, null would result in "null", "string" would result in '"string"', etc. This simplifies the code by a lot. The only restriction then becomes that all values must be a valid JSON value.
// see linked answer
function JSONstringifyOrder(obj, space)
{
const allKeys = new Set();
JSON.stringify(obj, (key, value) => (allKeys.add(key), value));
return JSON.stringify(obj, Array.from(allKeys).sort(), space);
}
class MySet extends Set {
// The constructor makes uses of add(), so we don't need
// to override the constructor.
has(item) {
return super.has(JSONstringifyOrder(item));
}
add(item) {
return super.add(JSONstringifyOrder(item));
}
delete(item) {
return super.delete(JSONstringifyOrder(item));
}
}
const set = new MySet([[1,2,3], [1,2,3], 1, 2, 1]);
set.add([1,2,3]);
set.add({ a: { s: 1, d: 2 }, f: 3 });
set.add({ f: 3, a: { d: 2, s: 1 } });
// Stack Overflow snippets cannot print Set instances to the console
console.log(Array.from(set));
// or unserialized
Array.from(set, json => JSON.parse(json)).forEach(item => console.log(item));

Automatically assign variables when destructuring large objects in ES6 [duplicate]

This question already has answers here:
How do I destructure all properties into the current scope/closure in ES2015?
(5 answers)
Closed 2 years ago.
I think I understand destructuring in ES6 well enough. Example:
const obj = {
foo: 'String1',
bar: 'String2'
}
let { foo, bar } = obj
console.log(foo) //Prints "String1"
Simple enough.
However, I have a large object with a dynamic number of properties with dynamic names. I'd like to be able to assign them automatically.
Example object:
const obj = {
a: 'String1',
b: 'String2',
c: 'String3',
// ....
y: 'String25',
z: 'String26',
}
Instead of declaring each variable individually, I tried:
// Instead of
// { a, b, c, d, so_on, y, z } = obj
// I try:
let { ...obj } = obj
But get this error:
Identifier 'obj' has already been declared
What's a better way to approach this?
As long as the identifier is different than that of the object you're trying to destructure it should work exactly as you intend it to.
const obj = {
a: 'String1',
b: 'String2',
c: 'String3',
// ...
y: 'String25',
z: 'String26',
}
const { a, b, ...rest } = obj
// const a: 'String1'
// const b: 'String2'
// const rest: {
// c: string;
// ...
// y: string;
// z: string;
// }
See this example in the playground.

Printing deepcopy of an object using custom function

I need to print elements of an object which is a deepcopy of another object using custom function. I am able to create deep copy using JSON parse/stringify trick but unable to implement print function.
var obj = {a:1,
b:{
a:2,
c:[1,2,3],
d:{
a:3
}
}
};
const mySnapShot = new Snapshot(object);
mySnapshot.print('a')// 1
.print('b.c') //[1,2,3]
.print('b.a') // 2
Arguments passed in print method are string. Snapshot is a class which contains methods for deep copy and print.
You can use reduce:
var obj = {
a: 1,
b: {
a: 2,
c: [1, 2, 3],
d: {
a: 3
}
}
};
function print(path) {
const pathTokens = path.split('.');
const pathValue = pathTokens.reduce((subObj, pathToken) => {
return subObj && subObj[pathToken] || null
}, obj);
return pathValue;
}
console.log(print('a')) // 1
console.log(print('b.c')) //[1,2,3]
console.log(print('b.a')) // 2

Is There a Object pollution while initializing values in a constructor using Object.keys?

I have an sample class defined as below
class Constants {
constructor(keysObj) {
this.keysObj = keysObj
Object.keys(this.keysObj).forEach((k) => this[k] = keysObj[k])
}
function getInformation() {
console.log("This is default function")
}
}
So when I create a object of above class - I can access the values as below
var newConsts = new Constants({
a: 1,
b: 2,
c: 3
})
// so I can access above values in this way
console.log(newConsts.c) // outputs 3
console.log(newConsts.getInformation) // outputs "This is default function"
Is code is vulnerable to Object Pollution ?
what I observed so far is - if I create a new object like this
var newConsts1 = new Constants({
a: 1,
b: 2,
getInformation: function() {
console.log('This is modifed')
}
})
// so I can access above values in this way
console.log(newConsts1.b) // outputs 2
console.log(newConsts1.getInformation) // outputs "This is modifed"
is Object pollution can be done on this class? if so please let me know what are the different ways to pollute it.
will this have any effect on the code
var newConsts3 = new Constants({
a: 1,
b: 2,
__Proto__: {
toString: function() {
console.log('faulty toString Executed')
}
}
})
var newConsts3 = new Constants({
a: 1,
b: 2,
prototype: {
construtor: undefined
}
}
})
the short answer is YES.
and this is because you are not checking in a safe mode that the keys that you are "initializing" are good or not, therefore, you can send anything to your object and make it vulnerable.

I am curious about javascript destructuring

The destructuring is one of the javascript syntax
This have been used like this.
const obj = { a: { A: 1, B: 2 } };
const { a } = obj // this is obj.a
const { B } = a // this is obj.a.B
the thing that I want to know is destructuring can save memory?

Categories

Resources