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
Related
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.
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));
I have some issues with getting prototype map function to work with my array object inside my object. I get the error "x() is not a function". I know that you cant use prototype on objects but arrays within objects should be reachable using obj.arr.map().
Here is my code:
let data = [
{'a':1, 'b':2, 'c':3},
{'a':4, 'b':5, 'c':6},
{'a':7, 'b':8, 'c':9}
]
let mapped = data.map(function(data){
let newMap = {}
newMap['a']=data['a']
newMap['b']=data['b']
return newMap;
});
Mapping.prototype.protoMap = function(){
//I have tried writing it as map.data
let protoMap = map.map(function(map){
let protoMap1 = {}
protoMap1['a'] = map.mappedData['a']
return protoMap1;
});
}
function Mapping(data = []){
this.mappedData = data
};
let map = new Mapping(mapped);
Try to stay away from using global variables:
Mapping.prototype.protoMap = function() {
// DON'T do this
// plus, this really doesn't make sense
// because `map` refers to the new `Mapping` object that
// you created; what you probably want to do is use the `mappedData`
// property on your newly created `Mapping` object
// const protoMap = map.mappedData.map(function(map) {...})
// instead, use `this` to access the `mappedData` property
// that you passed to the constructor
const protoMap = this.mappedData.map(function(item) {...})
}
const map = new Mapping(mapped)
See comments in the code snippet to figure out how to fix your example.
function Mapping(data = []) {
this.mappedData = data
}
Mapping.prototype.protoMap = function() {
// access the `mappedData` that was passed
// to the `Mapping` constructor using `this`
const protoMap = this.mappedData.map(
function(item) {
// use `item` argument for the `mappedData.map`
// callback to access each item inside `mappedData`
// individually
const temp = {}
temp["a"] = item["a"]
return temp
}
)
return protoMap
}
const data = [
{'a': 1, 'b': 2, 'c': 3},
{'a': 4, 'b': 5, 'c': 6},
{'a': 7, 'b': 8, 'c': 9}
]
const mapped = data.map(
function(data) {
const newMap = {}
newMap['a']=data['a']
newMap['b']=data['b']
return newMap;
}
)
const mapping = new Mapping(mapped)
const result = mapping.protoMap()
console.log('result', result)
You can use something similar to convert array to map. I have created this util long back ago.
More uses:
https://gist.github.com/deepakshrma/4b6a0a31b4582d6418ec4f76b7439781
class Mapper {
constructor(array, key) {
this.map = array.reduce((map, item) => {
const val = item[key];
if (!map[val]) {
map[val] = [];
}
map[val].push(item);
return map;
}, {});
}
find(key) {
return this.map[key] && this.map[key][Mapper.FIRST_INDEX]; //return blank array
}
findAll(key, returnUndefined) {
//return blank array
return this.map[key] ? this.map[key] : returnUndefined ? undefined : [];
}
}
Mapper.FIRST_INDEX = 0;
let data = [
{ a: 1, b: 2, c: 3 },
{ a: 4, b: 5, c: 6 },
{ a: 7, b: 8, c: 9 },
];
var dataMap = new Mapper(data, "a");
console.log(dataMap.map);
if(typeof window !== 'undefined') window.Mapper = Mapper;
Let's say I have an object where I want to keep internal-only key/pairs with symbols. Given...
let obj = {
[Symbol.for('foo')]: 'internal-only member',
a: 1,
b: 2,
c: 3
}
When I return these to a client through my API, I want to strip out all Symbols from the Object because the client doesn't have any use for them.
I'd like a generic function that will return:
{
a: 1,
b: 2,
c: 3
}
In other words:
returnScrubbedObj = (obj) => {
// filter/map/remove/copy etc the original object to a new object without symbols
return objWithoutSymbols
}
I know there are probably many different ways to do this; just looking for the best/most efficient one.
You could use JSON methods:
let obj = {[Symbol.for('foo')]:'internal-only member',a:1,b:2,c:3};
const res = JSON.parse(JSON.stringify(obj));
console.log(res);
A more verbose version using reduce and typeof:
let obj = {[Symbol.for('foo')]:'internal-only member',a:1,b:2,c:3};
const res = Object.entries(obj).reduce((acc, [k, v]) => typeof k == "symbol" ? acc : (acc[k] = v, acc), {});
console.log(res);
And since you asked about the efficiency, the reduce method is faster.
You could get the entries and build a new object of the entries.
let obj = {
[Symbol.for('foo')]: 'internal-only member',
a: 1,
b: 2,
c: 3
}
console.log(Object.fromEntries(Object.entries(obj)));
It is convenient and less memory and space intensive to use for .. in here on the object.
let obj = {
[Symbol.for('foo')]: 'internal-only member',
a: 1,
b: 2,
c: 3
}
let newObj = {};
for(let prop in obj) {
if(obj.hasOwnProperty(prop)){
newObj[prop] = obj[prop];
}
}
console.log(newObj);
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?