I have a 'getData' function which gets passed a 'data' variable. Inside the function I'm trying to access an object 'data.someObject' which may or may not exist because it comes from an outside library.
What is the best approach to check if it does exist before trying to use it? Also see I'm using object destructuring here aswell.
const getData = (data) => {
const { name, age } = data.someObject; // someObject may or may not exist
console.log(name, age);
}
I thought doing this might work:
const { name, age } = data.someObject || {};
But I wasn't sure if that would throw an error.
Thanks
You can use || & if required provide default values while destructuring.
function print(user) {
const { fname = "Anonymous", lname = "Panda" } = user.fullname || {};
console.log(`Hello ${fname} ${lname}`);
}
print({ fullname: { fname: "John", lname: "Doe" } });
print({});
print({ fullname: null });
Personally I would put an if statement:
const getData = (data) => {
if (data.someObject == null) {
// Here you can return, throw an error or do anything else you might need
}
const { name, age } = data.someObject; // someObject may or may not exist
console.log(name, age);
}
Related
I created a function that should return an object with user data. I want the function to accept an object as a parameter and I'd like this object to be defined inside the function with all the values pre-defined as default parameters in case they are not passed at a function call. The example code has only 2 values but I will need to pass over 15. How can I achieve such a solution?
const userCreator = (name, age) => {
if (name === undefined) {
name = 'John'
}
if (age === undefined) {
age = 25
}
return {
name:name,
age:age
}
};
...and I'd like this object to be defined inside the function with all the values pre-defined as default parameters in case they are not passed at a function call.
I think you're saying:
You want the function to accept an object
You want all the properties of that object to be optional with defaults specified by the function
To do that, you can use destructuring defaults. But see also below, because in this specific case, where you want to return an object, you may want to use a different approach.
But let's start with just basic destructuring without defaults, then add them:
const userCreator = ({ name, age }) => {
// ^−−−−−−−−−−−^−−−−−−−−−−−−−−−− destructuring
// ...stuff with `name` and `age` here...
return {
name,
age,
};
};
To add defaults for those properties, you add them within the destructuring pattern (the {} where the parameter name would otherwise be):
const userCreator = ({ name = "John", age = 25, }) => {
// ^^^^^^^^^−−−−−^^^^^−−−− defaults for the properties
return {
name,
age,
};
};
If there are lots, probably best to break up into lines:
const userCreator = ({
name = "John",
age = 25,
}) => {
return {
name,
age,
};
};
That version still expects an object to be provided, though. If you want to allow userCreator() (no parameter passed at all), you need to add a default parameter value for the object parameter:
const userCreator = ({
name = "John",
age = 25,
} = {}) => {
//^^^^−−−−−−−−−−−−−−−−−−−−−−−−−−− default for the parameter
return {
name,
age,
};
};
That uses {} as the default value if no parameter is provided at all, "John" as the default if name isn't provided, and 25 as the default if age isn't provided. And since there is no name or age on the default {}, they get defaulted when you do userCreator().
The alternative approach:
Since you want to return an object, you might just accept the object parameter directly, then use property spread or Object.assign to fill in defaults, like this:
const userDefaults = {
name: "John",
age: 25,
};
const userCreator = (template) => {
const result = { // The result object we'll return
...userDefaults, // Fill in defaults
...template // Overwrite with any properties from the caller
};
// Or with `Object.assign` in older environments without property spread:
//const result = Object.assign(
// {}, // The result object we'll return
// userDefaults, // Fill in defaults
// template // Overwrite with any properties from the caller
//);
return result;
};
Property spread and Object.assign both ignore null or undefined, so if no object is passed at all, template is undefined, and
You should define default values directly in the function parameters:
const userCreator = (name = 'John', age = 25) => {
return {
name: name,
age: age
}
};
I am following the redux tutorial https://redux.js.org/basics/actions and having a hard time understanding the following code
export function addTodo(text) {
return { type: ADD_TODO, text }
}
So the function above returns the object { type: ADD_TODO, text } and there are two things that confuse me.
what is the value of this object associated with the key text. If this value is undefined, then why not just return { type: ADD_TODO} instead.
If text is a string, then shouldn't it be { type: ADD_TODO, [text]: *some value* } instead?
Moreover, there are other functions like
function toggleTodo(index) {
return { type: TOGGLE_TODO, index }
}
function setVisibilityFilter(filter) {
return { type: SET_VISIBILITY_FILTER, filter }
}
Can someone explain this syntax to me?
They're using ES6 Shorthand property names - If the intended key name is the same as the variable, then you can simply pass the variable
let name = 'Jared';
let age = 19;
let literate = false;
let obj = {
name,
age,
literate
}
/* Is the same as...
let obj = {
'name': name,
'age': age,
'literate': literate
}
*/
console.log(obj);
The Problem:
I have this function. Which removes all KeyValue Pairs that have an Empty String as value from a Payload.
The problem is, that I want to apply it in an Object that is Nested. Not the whole Payload Object. Example:
configuration: {
conf1: "",
conf2: "Something",
conf3: ""
},
resourceName: "Name"
In this case I want to apply my UtilityFunction, in the configurationObject. Which would result in this:
configuration: {
conf2: "Something",
},
resourceName: "Name"
So, I used a few Methods. Object.assign, rest, in order to supply an object with all the outside parameters, but also, the output of the utility applied to just the configuration object.
I tried:
Object.assign(formValues, removeEmptyKeysUtil(formValues.configuration));
// Results in printing the values in the main object.
Also:
{ formValues, ...removeEmptyKeysUtil(formValues.configuration) };
// which does not do anything
Can you please help me, and explain what am I doing wrong?
The stripEmptyStrings function takes the original object and the target key.
this function can also handle if the target property of the object is "" and will delete that property regardless of if it is an Object or not.
const stripEmptyStrings = (object, target) => {
const _target = object[target];
if (_target === "") {
delete object[target]
return object;
}
else if (typeof _target === "object") {
Object.keys(_target).forEach((k) => {
if (_target[k] === "") delete _target[k];
})
}
return {
...object,
[target]: _target,
}
}
const obj1 = {
configuration: {
conf1: "",
conf2: "Something",
conf3: ""
},
resourceName: "Name",
}
const result1 = stripEmptyStrings(obj1, "configuration");
console.log(result1)
const obj2 = {
removeMe: "",
resourceName: "Name2",
}
const result2 = stripEmptyStrings(obj2, "removeMe");
console.log(result2)
I would like to get firstName and lastName properties from a whole user object. I need to use a conditional statement too.
How to do something like that?
getUserById(id)and getUserByAddress(id) use the JavaScript find() method that returns an element or undefined.
let { firstName, lastName } = getUserById(id);
if ({ firstName, lastName } === undefined) {
{ firstName, lastName } = getUserByAddress(id);
}
return `${firstName} ${lastName}`;
const { firstName, lastName } = getUserById(id) || getUserByAddress(id) || {};
if (firstName && lastName) {
return `${firstName} ${lastName}`;
}
return "Unknown user";
If getUserById(id) is falsy, getUserByAddress(id) will be executed. If this is falsy, too, {} will at least prevent throwing an error.
const episodeParser = (
query: string, codeType ?: string, productId?: number, newProductId?: number
) => {
let queryParams = {
query,
codeType,
processId : AppConfig.PROCESS_ID,
...(productId && {productId}),
...(newProductId && {newProductId})
};
return queryParams;
}
Here, productId and newProductId both are optional, whatever the value of id will be there, these key will be getting in queryParams.
Currently, when I want to prune an object (say, a user object that has details I don't want to send to the client), I have been copying over properties like so:
let user = db.findUser(_id);
//user = { username: "John", hashedPassword: "ashHDhadh23hfJAd", email: "John#doe.com", created: "<some date>" ... }
let forClient = {
username: user.username,
email: user.email
}
...
I am learning about destructuring an object in ES2015 and it seems like it might be possible to do this more cleanly. Is it?
Destructuring won't help here without introducing overhead. It simplifies creating variables from an object, i.e. if you would use it here, it result in something like this:
let { username, email } = user;
let forClient = { username, email };
But as you can see, this adds new variables and repeats code.
You could consider using reduce to select the wanted fields:
let forClient = ['username', 'email'].reduce((v, k) => { v[k] = user[k]; return v }, {});
... or with a higher-order function to not repeat too much code:
const selectFrom = (obj) => (v, k) => { v[k] = obj[k]; return v };
let userForClient = ['username', 'email'].reduce(selectFrom(user), {});
let postForClient = ['title', 'summary'].reduce(selectFrom(blogpost), {});
// etc.
... or just add a function like this to your library, which uses the rest spread operator for simple usage:
function pruneObject(obj, ...fields) {
let pruned = {};
fields.forEach(f => pruned[f] = obj[f]);
return pruned;
}
let forClient = pruneObject(user, 'username', 'email');