Javascript - any kind of rest operator that skips undefined properties? - javascript

I have this:
var filters = {a: 1, b: undefined}
And I want this:
{ a:1 }
Is there any way of getting the object above by using modern Javascript features like {...filters} ?

Unless you know in advance a singular property which is undefined, it's not possible with rest syntax, or anything new like that, though you can achieve it by serializing and deserializing the object. The code is short, but it's inelegant and only works when everything in the object is serializable:
var filters = {a: 1, b: undefined};
var filtersNoUndef = JSON.parse(JSON.stringify(filters));
console.log(filtersNoUndef);
Or, of course, you can iterate over the properties manually:
var filters = {a: 1, b: undefined};
const filtersNoUndef = { ...filters };
Object.entries(filtersNoUndef).forEach(([key, val]) => {
if (val === undefined) {
delete filtersNoUndef[key];
}
});
console.log(filtersNoUndef);

An alternative using the function reduce
let filters = {a: 1, b: undefined};
let result = Object.entries(filters).reduce((a, [key, value]) => value === undefined ? a : Object.assign(a, {[key]: value}), Object.create(null));
console.log(result);

Related

Spread inside JSON reviver function

I Would like to be able to spread out the value of an entry inside a JSON.parse reviver function while also drop the original key.
Returning a spreaded value doesn't seem to do that trick.
here is an example:
const json = {a: 'foo', b: {c: 1, d: '2'}}
const stringify = JSON.stringify(json)
const parsed = JSON.parse(stringify, function(k, v) {
if(k === 'b') {
return {...v}
} else {
return v
}
})
document.getElementById("app").innerHTML = `<pre>${JSON.stringify(parsed, null, 2)}</pre>`;
<div id="app"></div>
In the above the desired output should be
{
"a": "foo",
"c": 1,
"d": "2"
}
While I wouldn't recommend it as it's not very intuitive, you can use Object.assign(this, v) to merge with the this value in your replacer. This merges object at the b property into the object that the b property appears in, temporarily giving you:
{a: 'foo', b: {c: 1, d: '2'}, c: 1, d: '2'}
and then b is removed as we return undfined for that path, giving:
{a: 'foo', c: 1, d: '2'}
const json = {a: 'foo', b: {c: 1, d: '2'}};
const stringify = JSON.stringify(json)
const parsed = JSON.parse(stringify, function(k, v) {
if(k === 'b') {
Object.assign(this, v);
} else {
return v;
}
});
document.getElementById("app").innerHTML = `<pre>${JSON.stringify(parsed, null, 2)}</pre>`;
<div id="app"></div>
JSON.parse reviver only transform the value that is at key "b" and set it on that key. I would picture it similar to a map.
Your solution should be outside the reviver function. Here is a sample of how your code could look like:
let { b, ...parsed } = JSON.parse(stringify);
if (b) {
parsed = { ...parsed, ...b };
}
#Geo Mircean answer is correct, but your comment add new information to the question.
If you have a complex structure, I don't think there is an easier option. The first one that comes to mind is to iterate the object and see if you need to spread each field. The logic to tell if you need to spread is up to you, but it will be something like:
let parsed = {...jsonObject};
for(let key in jsonObject)
{
if (typeof jsonObject[key] === 'object') // if you want to spread
{
delete parsed[key]; // delete the actual key
Object.assign(parsed, jsonObject[key]); // add fields to object
}
}
Notice that the parsed variable will have our result. At first it get the whole object, then we iterate over the result, delete the field and spread the field value itself.
The Object.assign came from this StackOverflow question and does not work in IE9 (but I personally don't care about that).

javascript functional programming External Dependence mutation

Can someone explain this javascript behavior?
let a = {z: true};
console.log(a);
const modify = obj => {
let b = {
a: "hello",
b: 22
}
obj = {...obj, ...b}
return obj;
}
modify(a);
console.log(modify(a))
output:
{
z:true,
a:"hello",
b:22
}
is obj in obj = {...obj, ...b} an implicitly new created object or is this the same obj parameter of modify.
because when I try to comment the return obj; line (//return obj;) in a visual studio text editor the parameter obj inside the modify function seems to be faded meaning that I'm not using it inside the function. Also without having to return obj; i just wanted to alter a given object and bind to it some new properties. is this possible?
The object in your code is not mutated. The object literal notation (with { }) always creates an object. Secondly, the assignment to obj is to the local variable with that name, not the variable of the caller (a). To mutate the given object, you can use Object.assign:
let a = {z: true};
console.log(a);
const modify = obj => {
let b = {
a: "hello",
b: 22
}
// The return is not absolutely necessary...
return Object.assign(obj, b);
}
modify(a);
console.log(a);
Of course, when you let functions mutate objects, you are no longer in line with functional programming principles.
obj = {...obj, ...b} will create a new object.
If you want to change the given object just change his properties:
const modify = obj => {
obj.a = "hello"
obj.b = 22
}
If you want to combine new object to your existsing object you can also use Object.assign:
Object.assign(obj, b)

using optional chaining in array of object and destructing

I have an object like this
const obj = [{a: 'a'}];
I can get it like:
const { a } = obj[0]; //a
but what if obj['x'] doesn't exist?
I tried this with optional chainning but doesn't seem to work.
const { a } = obj?.[1];
You are close to it. You should make sure to fallback with an empty object, for the destructing later to make sense
const obj = [{a: 'a'}];
const { a } = obj?.[1] || {};
console.log(a)
Update
This would be even shorter if you don't use destructing in this case
const obj = [{a: 'a'}];
const a = obj?.[1]?.a; // or: obj?.[1]?.['a']
console.log(a)
You can use the Logical OR operator.
const { a } = obj[x] || {}
If obj does not have a property x, a will be set to undefined.
You could festructure with an index as computed property and a default object for a missing item of the array.
const
obj = [{ a: 'a' }],
{ [2]: { a } = {} } = obj;
console.log(a);
Take a look at the following three cases, where I've used optional chaining.
You need to first check if the first element of the array (index 0) exists and then check if there's a field a in it.
// Case 1:
const obj1 = [{ a: "a" }];
console.log(obj1?.[0]?.a); // "a"
// Case 2:
const obj2 = [{ b: "b" }];
console.log(obj2?.[0]?.a); // undefined
// Case 3:
const obj3 = [];
console.log(obj3?.[0]?.a); // undefined

Extending object's properties without overwriting them

I'm trying to extend the keys/values in target object (with the keys/values) from source object, but without overwriting existing keys/values in the target object. Meaning:
var obj1 = {
a: 1,
b: 2
};
var obj2 = {
b: 4,
c: 3
};
extend(obj1, obj2);
console.log(obj1); // --> {a: 1, b: 2, c: 3}
Interestingly, I found Object.assign(obj1,obj2);, but it overwrites the keys/values.
I need to not overwrite them, if existent and add them if nonexistent.
Please help in plain JavaScript.
Just a simple loop. If you only want enumerable own properties, then:
Object.keys(obj2).forEach(function(key) {
if (!(key in obj1)) {
obj1[key] = obj2[key];
}
});
If you want all enumerable properties:
var key;
for (key in obj2) {
if (!(key in obj1)) {
obj1[key] = obj2[key];
}
}
The key (no pun) bit there is the in operator, which tells you whether an object has a property (of its own, or via inheritance).
There's also Object.prototype.hasOwnProperty which would tell you only if the object has its own (not inherited) property with a given name:
Object.keys(obj2).forEach(function(key) {
if (!obj1.hasOwnProperty(key)) {
obj1[key] = obj2[key];
}
});
More:
in operator
hasOwnProperty
There is no such built in functions available in JS to do that for you.
You have to write your own logic to do that,
var x = {a:10};
var y = {a:5, b: 20};
merge(x,y);
function merge(objSrc, objTarget){
return Object.keys(objTarget).reduce(function(src, prop){
if(!src.hasOwnProperty(prop)) src[prop] = objTarget[prop];
return src;
}, objSrc);
}
console.log(x); {a:10, b:20}
P.S The above code would do a merge over enumerable own properties since Object.keys() would return the same.

Javascript - removing undefined fields from an object [duplicate]

This question already has answers here:
Remove blank attributes from an Object in Javascript
(53 answers)
Closed 5 years ago.
Is there a clean way to remove undefined fields from an object?
i.e.
> var obj = { a: 1, b: undefined, c: 3 }
> removeUndefined(obj)
{ a: 1, c: 3 }
I came across two solutions:
_.each(query, function removeUndefined(value, key) {
if (_.isUndefined(value)) {
delete query[key];
}
});
or:
_.omit(obj, _.filter(_.keys(obj), function(key) { return _.isUndefined(obj[key]) }))
A one-liner using ES6 arrow function and ternary operator:
Object.keys(obj).forEach(key => obj[key] === undefined ? delete obj[key] : {});
Or use short-circuit evaluation instead of ternary: (#Matt Langlois, thanks for the info!)
Object.keys(obj).forEach(key => obj[key] === undefined && delete obj[key])
Same example using if statement:
Object.keys(obj).forEach(key => {
if (obj[key] === undefined) {
delete obj[key];
}
});
If you want to remove the items from nested objects as well, you can use a recursive function:
const removeEmpty = (obj) => {
let newObj = {};
Object.keys(obj).forEach((key) => {
if (obj[key] === Object(obj[key])) newObj[key] = removeEmpty(obj[key]);
else if (obj[key] !== undefined) newObj[key] = obj[key];
});
return newObj;
};
I prefer to use something like Lodash:
import { pickBy, identity } from 'lodash'
const cleanedObject = pickBy(originalObject, identity)
Note that the identity function is just x => x and its result will be false for all falsy values. So this removes undefined, "", 0, null, ...
If you only want the undefined values removed you can do this:
const cleanedObject = pickBy(originalObject, v => v !== undefined)
It gives you a new object, which is usually preferable over mutating the original object like some of the other answers suggest.
Use JSON Utilities
Overview
Given an object like:
var obj = { a: 1, b: undefined, c: 3 }
To remove undefined props in an object we can use nested JSON methods stringify and parse like so:
JSON.parse(JSON.stringify(obj))
Live Example
var obj = { a: 1, b: undefined, c: 3 }
var output = JSON.parse(JSON.stringify(obj));
console.log(output)
Limitations and warnings
Depending on how Javascript is implemented.
It is possible that undefined will be converted to null instead of just being removed.
Nested Object, Array will be converted to strings
Date, time values also converted to strings
Tested
The above code was tested in Firefox, Chrome, and Node 14.18.1 and removed "b" from all obj arrays. Still I recommend exercising caution using this method unless you are in a stable environment (such as cloud functions or docker) I would not rely on this method client side.
Because it doesn't seem to have been mentioned, here's my preferred method, sans side effects or external dependencies:
const obj = {
a: 1,
b: undefined
}
const newObject = Object.keys(obj).reduce((acc, key) => {
const _acc = acc;
if (obj[key] !== undefined) _acc[key] = obj[key];
return _acc;
}, {})
console.log(newObject)
// Object {a: 1}
This solution also avoids hasOwnProperty() as Object.keys returns an array of a given object's own enumerable properties.
Object.keys(obj).forEach(function (key) {
if(typeof obj[key] === 'undefined'){
delete obj[key];
}
});
and you can add this as null or '' for stricter cleaning.
Here's a plain javascript (no library required) solution:
function removeUndefinedProps(obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop) && obj[prop] === undefined) {
delete obj[prop];
}
}
}
Working demo: http://jsfiddle.net/jfriend00/djj5g5fu/
Mhh.. I think #Damian asks for remove undefined field (property) from an JS object.
Then, I would simply do :
for (const i in myObj) {
if (typeof myObj[i] === 'undefined') {
delete myObj[i];
}
}
Short and efficient solution, in (vanilla) JS !
Example :
const myObj = {
a: 1,
b: undefined,
c: null,
d: 'hello world'
};
for (const i in myObj) {
if (typeof myObj[i] === 'undefined') {
delete myObj[i];
}
}
console.log(myObj);
This one is easy to remember, but might be slow. Use jQuery to copy non-null properties to an empty object. No deep copy unless you add true as first argument.
myObj = $.extend({}, myObj);
Another Javascript Solution
for(var i=0,keys = Object.keys(obj),len=keys.length;i<len;i++){
if(typeof obj[keys[i]] === 'undefined'){
delete obj[keys[i]];
}
}
No additional hasOwnProperty check is required as Object.keys does not look up the prototype chain and returns only the properties of obj.
DEMO

Categories

Resources