I have a specific use case where I want to do a nested de-structuring and assign an alias (rename it to another variable name, say aliasD) as well as a default value to a property. E.g.
const a = { b: { c: [{ d: 'value' }] } };
and while destructuring I only need d but with an alias aliasD and a default value defaultVal. SO I tried below, but I am not sure what I am missing
const a = { b: { c: [{ d: 'value' }] } };
const { b: { c: [first: { d: aliasD = defaultVal }] } } = a;
console.log(aliasD);
But this doesn't work
The problem here is for destructuring the array, the correct syntax to get the first value of the array would be:
[varName] = yourArray
Applying that to your example:
const { b: { c: [{ d: aliasD = 'test' }] } } = a;
You can try it out with Babel REPL
Related
I want to remove all empty objects from another object by comparing it with another. Example of this would be:
We have default object like:
defaultObj = {
a: {},
b: {},
c: {
d: {}
}
};
And target object like this:
targetObj = {
a: { x: {} },
b: {},
c: {
d: {},
e: {}
},
f: {}
};
Now, I need to perform operation on targetObj by comparing it with defaultObj, and remove all objects that remain empty, but leave every object in targetObj that weren't originally in default.
Result of operation should look like this:
result = {
a: { x: {} },
c: {
e: {}
},
f: {}
}
Here is a solution that you can use which recursively iterates an object and removes the empty properties as defined in your use case. Make sure to create a deep copy of the object first (as shown in the example) so that the original does not get manipulated:
const defaultObj = {
a: {},
b: {},
c: {
d: {}
}
};
const targetObj = {
a: { x: {} },
b: {},
c: {
d: {},
e: {}
},
f: {}
};
// traverse the object
function removeEmptyObjectProperties(targetObject, defaultObject) {
Object.keys(targetObject).forEach((key) => {
if (defaultObject.hasOwnProperty(key)) {
// checks if it is a json object and has no keys (is empty)
if (targetObject.constructor === ({}).constructor && Object.keys(targetObject[key]).length === 0) {
delete targetObject[key];
} else {
// iterate deeper
removeEmptyObjectProperties(targetObject[key], defaultObject[key]);
}
}
})
}
// deep copy to remove the reference
const targetObjDeepCopy = JSON.parse(JSON.stringify(targetObj));
// execute
removeEmptyObjectProperties(targetObjDeepCopy, defaultObj);
// result
console.log(targetObjDeepCopy)
I have an array of objects I want to destructure, retrieving both the first object and a value within it:
const [{ a }] = ([firstObjectInArray] = [
{
a: 1,
},
{
b: 2,
},
]);
console.log(a); // 1
console.log(firstObjectInArray); // { a: 1 }
In Javascript this works; but in TypeScript this returns
Cannot find name 'firstObjectInArray'.ts(2304)
I'm trying to figure out how to type that in order to avoid the error.
As firstObjectInArray isn't part of your declaration (it's just an expression), it's an assignment to an undeclared variable.
To solve the issue, you have two ways:
Do it in two steps:
const [firstObjectInArray] = [
{
a: 1,
},
{
b: 2,
},
];
const {a} = firstObjectInArray
console.log(a); // 1
console.log(firstObjectInArray); // { a: 1 }
Declare the firstObjectInArray earlier:
let firstObjectInArray; //<-- This can't be made `const`, as it has no initializer
const [{ a }] = ([firstObjectInArray] = [
{
a: 1,
},
{
b: 2,
},
]);
console.log(a); // 1
console.log(firstObjectInArray); // { a: 1 }
This question already has answers here:
How to deep merge instead of shallow merge?
(47 answers)
Closed 2 years ago.
I have a nested default object that I want to both extend and overwrite with nested properties. I tried with the spread operator but you can also use Ojbect.assign.
The problem is that nested objects get overridden instead of their respective properties getting overridden and/or extended.
const defaultOptions = {
a: 0,
b: 1,
c: {
hello: 'world',
age: 20
}
};
const specialOptions = {
b: 0,
c: {
age: 10
},
d: 1
};
const options = {
...defaultOptions,
...specialOptions
}
console.log(options)
const expectedOptions = {
a: 0,
b: 0,
c: {
hello: 'world',
age: 10
},
d: 1
}
console.log(expectedOptions)
Update 2021-08-24
It seems this question is a duplicate of another so therefore I will delete it.
Here is a recursive solution, although it mutates the input object and doesn't return a new one, as I would've wanted. Hence why I added the deepCopy function.
Also, the order isn't maintained. But I assume that isn't of the biggest concern if you are using objects in the first place.
const defaultOptions = {
a: 0,
b: 1,
c: {
hello: 'world',
age: 20
}
}
const specialOptions = {
b: 0,
c: {
age: 10
},
d: 1
}
const deepCopy = obj => JSON.parse(JSON.stringify(obj))
const options = deepCopy(specialOptions)
const extendObj = (defaults, obj) => {
Object.entries(defaults)
.forEach(([key, value]) => {
if (obj[key] === undefined) {
obj[key] = value
} else if (typeof value === 'object') {
extendObj(defaults[key], obj[key])
}
})
}
extendObj(defaultOptions, options)
console.log(options)
I wanted to contribute a fix for this to the lodash repo but thought I should check that I'm not doing something wrong first...
When I use standard lodash in this example...
const _ = require('lodash');
run = () => {
const mapping = {
a: 'hello',
b: 'world'
};
const object = {
a: { value: true },
b: { value: false }
};
// this is the original transform function that takes three arguments...
// 1. the object to be transformed
// 2. the transform function
// 3. the accumulator object
const transformed = _.transform(
object,
(a, v, k, o) => { a[mapping[k]] = _.get(v, 'value'); },
{}
);
console.log(transformed);
};
run();
The output is { hello: true, world: false } like I expected.
When logging a, v, k, and o on the above code the output is...
1 a: {}
1 v: { value: true }
1 k: a
1 o: { a: { value: true }, b: { value: false } }
2 a: { hello: true }
2 v: { value: false }
2 k: b
2 o: { a: { value: true }, b: { value: false } }
However, when I run (what I think is) the equivalent code using lodash/fp...
const _ = require('lodash/fp');
run = () => {
const mapping = {
a: 'hello',
b: 'world'
};
const object = {
a: { value: true },
b: { value: false }
};
// this is the fp transform function that takes two arguments...
// 1. the transform function
// 2. the accumulator object
// it then returns a function that takes one argument...
// 1. the object to be transformed
const transformed = _.transform(
(a, v, k, o) => { a[mapping[k]] = _.get('value')(v); },
{}
)(object);
console.log(transformed);
};
run();
The output is { undefined: false }. This is because the parameters to the iterator do not seem to be correct. When I log a, v, k, and o I get the following output...
1 a: {}
1 v: { value: true }
1 k: undefined
1 o: undefined
2 a: { undefined: true }
2 v: { value: false }
2 k: undefined
2 o: undefined
Am I doing something wrong or is this not working as expected?
I have also added this as an issue on the repo but thought I'd add here as maybe I would get a faster response :D
https://github.com/lodash/lodash/issues/4381
Try this:
const transform = _.transform.convert({ cap: false });
const transformed = transform(
(a, v, k, o) => { a[mapping[k]] = _.get('value')(v); },
{}
)(object);
pen
OK, it's very odd but I can get it working.
When using lodash/fp the autocompletion of the iteratee shows the function signature like...
function(accumulator, currentValue) {}
So it will only accept two arguments (which is what is said in the documentation linked to by #charlietfl).
However, when I create the function like this...
function(a, v) {
console.log(arguments.length);
}
It outputs 4.
So I kept exploring...
function(a, v) {
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
console.log(arguments[3]);
}
This outputs...
1 a: {}
1 v: { value: true }
1 k: a
1 o: { a: { value: true }, b: { value: false } }
2 a: {}
2 v: { value: false }
2 k: b
2 o: { a: { value: true }, b: { value: false } }
Just like I wanted it to. So, even though the function is only declared with 2 arguments and only accepts 2 parameters, 4 arguments are actually passed into it.
So, when I update the code like this...
function(a, v) {
const k = arguments[2];
a[mapping[k]] = v.value;
}
This returns { hello: true, world: false } which is what I was hoping to get in the first place.
I can get around it this way but don't understand why this is happening. So, because of that I'm going to stick with my current method of mapKeys followed by mapValues and TBH... I'll probably be looking at dropping lodash in the near future and writing my own functions to replace this functionality.
I am working with JavaScript, could you help me please
Here is my problem.
I have this object:
var MyObj= [{ a: 0, b: "Zero", c: "x", d: "!" }, { a: 1, b: "One", c: "y", d: "#" }]
I want to change the element of selected object ("a" --> "id") to become like this:
var NewObj= [{ id: 0, b: "Zero", c: "x", d: "!" }, { id: 1, b: "One", c: "y", d: "#" }]
I tried to use $.map() method like this
NewObj= $.map(MyObj, function (obj) {
return { id: obj.a, b: obj.b, c: obj.c, d:obj.d };
});
Is there any better way to do this since I only change one element of object?
No need for ES6 / Object.assign, no need for jQuery:
Working Fiddle: https://jsbin.com/gosaqid/edit?js,console
function makeObj(obj){
return obj.map(function(el, i) {
el.id = i;
delete el.a;
return el;
});
}
Not unless you have a clone/copy/extend function available. One is coming up in new JavaScript, and jQuery has one, and it's not very hard writing your own. But it still isn't a walk in the park - you can't just rename a property, you need to copy and delete:
NewObj = MyObj.map(function(obj) {
var newobj = Object.assign({}, obj, {id: obj.a});
delete newobj.a;
return newobj;
});
In your example MyObj is an array of objects.
var object = {}
var array = []
var arrayOfObjects = [{}, {}, {}]
In your desired result, you have changed one of the keys of every object in the array.
Using map is a perfectly adequate way of doing this, in fact JavaScript's array has a built in map method.
var newArrayOfObjects = arrayOfObjects.map(function (obj) {
return {
id: obj.a,
b: obj.b,
c: obj.c
}
})
If you have a ton of keys this can get a little verbose so you can use $.extend, but chances are you're writing code for modern browsers so the whole thing can be written as such:
var newArrayOfObjects = arrayOfObjects.map(obj =>
Object.assign({}, obj, { id: obj.a })
)
update: as #Amadan suggests, you can also delete the old key if you need