This question already has an answer here:
ES6 Object Destructuring Default Parameters
(1 answer)
Closed 6 years ago.
When destructuring objects, I sometimes run into the issue of not knowing whether or not keys exist, and then trying to pull values from them. This obviously errors, since they are undefined. For example:
Expecting something like this:
{ user: { name: { first: 'Trey', last: 'Hakanson' } } }
But I actually get this:
{ user: {} }
and attempting to destructure like this errors:
const { user: { name: { first: firstName, last: lastName } } } = data
is there any way to assign a default value earlier in the deconstruction? Such as assigning name = { first: 'Hello', last: 'World' } if the name key doesn't exist?
const { user: { name: { first: firstName = 'firstName', last: lastName = 'lastName' } = {} } = {} } = data
You can assign default values if the value is falsy value or undefined in your case. In javascript the default values can be assigned by using the || operator.
If the first operand is falsy (false, null, undefined, "",0) then it returns the second operand. Otherwise, it returns the first operand. This provides a convenient way to specify default values
var myDefaultName = name || { first: 'Hello', last: 'World' }
Related
The function I declared takes an object and an array of keys to ensure that the object has the correct keys. I also want to validate the values if they are not empty and check their types as well.
isObjectEmpty(obj) is a function that checks if object is not empty
While it works for keys, I am not sure how to check the types of values and their data
const localStorageDataValidation = (obj, whiteList) => {
if (!isObjectEmpty(obj)) {
const newObj = Object.fromEntries(
Object.entries(obj).filter(([key, value]) => {
return whiteList.includes(key);
}),
);
return newObj;
}
}
my object looks like this:
const obj = {
user: {
name:"",
email: "",
lastName: "",
},
userOrders: [{id: "1", count: 2, price: 2, title: ""}];
adress: {street: "", location: ""};
delivery: 1;
}
You can add another filter after the first one to validate the values. You can use typeof to check the type and check if the value is not an empty string or undefined.
I have a method for handling an update on this object. In this method I want to accept any field value that the object has, such as name, age, weight, eyeColor etc. If that field exists within that object, I'd like to be able to update the object dynamically for any field they pass in.
I am currently doing it incorrectly I believe with the spread operator while trying to update one field in the object. There is an error that fieldName does not exist within myObject. Does anyone know how to do this dynamically without need for a long switch statement checking each of the fields against fieldName passed in? In previous attempts tweaking with this I have successfully added a new field to the object named "fieldName" which is also not what I wanted.
If anyone has any ideas, that would be so helpful, thank you!
let myObject = {
name: 'John',
lastName: 'Smith',
age: 26,
weight: 200,
eyeColor: 'blue',
hairColor: 'blonde'
};
const handleUpdate = (fieldName: string, fieldValue: string | number) => {
if (fieldName in myObject) {
myObject = {...myObject, fieldName: fieldValue};
}
}
handleUpdate('name', 'Jack'); // Want this call to update the name of 'John' to 'Jack'
In short, you're looking for:
{...myObject, [fieldName]: fieldValue}
You can make a generalized, typesafe function to do this as follows:
function updateProp<TObj, K extends keyof TObj>(obj: TObj, key: K, value: TObj[K]) {
return {...obj, [key]: value};
}
and call it as follows:
const foo = { a: 1, b: "monkey" };
const updatedFoo = updateProp(foo, "b", "hello world")
Playground Link
You're looking for the Bracket notation property accessor:
myObject[fieldName] = fieldValue
Compared to the approach with the spread operator, this does actually update the object in place. I.e. if the reference in myObject was previously copied elsewhere, that reference will also "see" the updated field.
Whereas, by overriding the value with myObject = {...myObject}, you're creating a new object each time.
tl;dr: Is it a good practice to use undefined as a value or should I avoid it and try with another aproach?
I have an object which I use as a schema for my two functions createUser() and updateUser() and based on what values I need, I reconfigure it.
For updateUser() I need to send only the keys user entered in a form so the only way I know of, without changing the structure of the object manually, is to set the values to undefined.
// d is passed as argument
const args = {
variables: {
where: {id: "someValue"},
data: {
username: d.username || undefined,
password: d.password || undefined,
role: d.role || undefined,
},
},
};
Now if I have entered only username, my object will be
variables: {
where: { id: "someValue"},
data: { username: "anotherValue" }
}
I have given it a second thought after ESLint gave me a warning "Unexpected use of undefined."
NOTE I can't send empty values to API. It has to have either value or not send the key at all.
const args = {
variables: {
where: {id: "someValue"},
data: {
username: d.username || "",
password: d.password || "",
role: d.role || "",
},
},
};
It makes more sense to use empty values instead of keeping them undefined, or you can use null.
So, that your API contracts won't get violated.
It's difficult to determine what good is and isn't, because it's always all about the needs and preferences of the client and your teammates.
The very simple and short answer to the question is: yes. undefined is a valid value and if this would be an evidently bad practice, then the language would not allow that value to be assigned. However, it's important to make sure that you do not duplicate your values. Taking a look at this object
{
variables: {
where: {id: "someValue"},
data: {
username: d.username || undefined,
password: d.password || undefined,
role: d.role || undefined,
},
},
};
we see that you repeat the same idea over and over again. Instead, you would do better to implement something like this:
function nicify(object) {
for (var key in object) {
if (!object[key]) object[key] = undefined;
else if ((typeof(object[key]) === "object") || (Array.isArray(object[key]))) {
nicify(object[key]);
}
}
}
the function above recursively does what you wanted to do with your attributes. This will be very helpful if you have many attributes and/or many use-cases. Also, if you consistently have the pattern of having a source object as in your example, then you can implement something like this:
function fillBySource(object, source) {
for (var key in source) {
object[key] = source[key] || undefined;
}
}
I think || null or || '' are better practise, if you JSON.stringify() to exchange data with a server or something nothing in the JSON tell you that a username and a password should be present in the data prop. You can see that in the following eg :
function test(username, password, role) {
const args = {
variables: {
where: {id: "someValue"},
data: {
username: username || undefined,
password: password || undefined,
role: role || undefined,
},
},
};
return JSON.stringify(args);
}
let json = test();
console.log(json);
To my best of knowledge, you should not assign undefined the way you are currently doing it, because if d.username in the code is not set, then it's value is already undefined.
Usually the use case for assigning undefined is when a variable is initially set, but you want to unset/reset it as if the value was never set in the first place.
Ho can I avoid to write all fields with = ""?
const defaultPlayer = {
name: "",
surname: "",
age: "",
skill: ""
}
// ...
mapPropsToValues = ({ player }) => player || defaultPlayer
Is there in javascript that I can use to avoid write all the time = ""?
I mean, if I already know that defalut value of every field is "" (empty string) how can I do instead of write every field explicitly?
You can accomplish this using a with block and a Proxy object and eval:
let defaultPlayer;
with (new Proxy({}, {
has(o, key) {
try { eval(key); }
catch (e) { return true; }
},
get() {
return '';
}
})) {
defaultPlayer = {
userName,
age,
surname,
isAdmin: false
};
}
console.log(defaultPlayer);
When you omit a property value, it looks for a variable with the same name as the key. For example, {x} is the same as {x: x}. We can use the with() statement to have JavaScript check for properties of an object before looking for variables. Instead of a normal object, we'll define a Proxy that returns '' for any variables that it doesn't see in the local environment (by testing for an exception when evaling their name).
☠️ This is an obscene hack with nasty edge cases. Never use it. ☠️
I need to take this object, check each properties truthyness, and then remove the untruthy ones.
var user = {
name: 'my name',
email: null,
pwHash: 'U+Ldlngx2BYQk',
birthday: undefined,
username: 'myname33',
age: 0
}
Here is the code I was trying
function truth(x) {
if (x) {
console.log("truthy");
} else {
delete;
}
}
for (x in user) {
truth(user[x]);
}
but it's not working and I'm not even sure I fully understand how to make sure I'm checking truthy right. what am I doing wrong?
You have to specify both the object and the property when you delete it.
It's not enough with just the value copied from the property that you pass to the function, so you can't do it in that function (unless you also pass in the object reference and the property name).
for (x in user) {
if (user[x]) {
console.log("truthy");
} else {
delete user[x];
}
}