Trying to see if object key exists keep getting undefined - javascript

I have a data response that responds with different objects in an array.
I have tried a variety of different methods to determine if the key 'name' exists including:
const hasName = array.forEach(item => "name" in item )
const hasName = array.forEach(item => Object.keys(item).includes('name') )
const hasName = array[0].hasOwnProperty("name") ? true : null
const hasName = array => array.some(x => x.some(({ name }) => name));
// lodash 'has' method
const hasName = has(array, 'name')
Array1 returns objects like:
[
{
name: 'cool name'
}
]
Array2 returns objects like:
[
{
group: 'cool group'
}
]
All of the methods I tried have either returned undefined or nothing at all and I'm completely at a loss for why. I have scoured Stack Overflow and the internet trying to get a better direction or an answer but I haven't been able to find anything.

You're not returning anything from some of your calls on the array. forEach for example runs a callback, and always returns undefined see docs. Your code just isn't working because you're using the functions incorrectly.
The code below filters your array to get the elements with a name property, then counts them to see whether one or more exists, which results in a true or false being stored in the hasName variable.
let myArr = [
{
name: 'cool name'
}
]
const hasName =
myArr
.filter(a => a.hasOwnProperty("name")) // filter for elements in the array which have a name property
.length // get the number of filtered elements
> 0 // check whether the number of elements in array with name prop is more than 0
console.log(hasName)

If you are sure that the "response" is fully received before the check, THEN
Your latest variant of the check can be implemented as follows:
array.some(obj => (obj.name !== undefined)); // fast, but not define .name if it is "undefined"
array.some(obj => obj.hasOwnProperty("name")); // slower, but will define .name with any value
Your solutions are generally correct, but it looks like you're a little confused,
Array.forEach always returns "undefined":
array.forEach(obj => {
console.log("name" in obj); // true for 1st array
console.log("group" in obj); // true for 2nd array
}); // return "undefined"
array[0].hasOwnProperty() works fine, and can't return "undefined" at all.
console.log(
array[0].hasOwnProperty("name") ? true : null; // return ("true" for the 1st array) AND ("null" for the 2nd)
);
When you used the Lodash, maybe you forgot to point to the object index?
_.has(array[0], 'name'); // return ("true" for the 1st array) AND ("false" for the 2nd)

Try a for loop
for (var i = 0; i < array.length; i++) {
if (array[i].hasOwnProperty('name')) {
console.log(array[i].name); //do something here.
break;
}
}

Related

How can I filter the result of a ternary that's inside a map?

I'm 100000% new to the ternary world, so I really don't understand what's going on. I have the following:
categories.forEach((category) => {
const errorCategory = {
[category]: response.map(
(r) => r.ds_category === category && r.ds_name
),
};
errors = { ...errors, ...errorCategory };
});
I want to filter the r.ds_name to remove all "false" results, how could I do this? I tried:
Doing the filter straight away (r.ds_name.filter(blablabla)) but I get a "this is not a function" error.
Switching from ternary to the old school function, and didn't get any results either.
Filtering errorCategory (errorCategory = errorCategory.filter((item) => item === "false"), but I also got the "this is not a function" error.
Thanks :(
To filter an array, I'd recommend using '.filter' instead of '.map'. This will remove the elements which do not match the requirement set. Assuming response is an object which is an array, or other object which implements 'filter', you can do the following (note the extra brackets):
categories.forEach( ( category ) => {
const errorCategory = {
[ category ]: response.filter(
(r) => (r.ds_category === category && r.ds_name)
),
};
//Do stuff
}
You can use ternary operator in a filter method like this
const newArray = array.filter( element => {
element.property === "text" ? true : false
})
It check for element.property is equal to "text". If it is equal it returns true. If not returns false. But you dont need to do that. You can simply do this
const newArray = array.filter( element => {
element.property === "text"
})
This would return the same result

Destructuring fallback to prevent undefined error?

I have a list of array I do this:
const { id } = myArray.find(
(obj) => obj === true)
If the id is not present it will throw error. How to prevent error in the same time use destructuring? I want to keep the logic in one line.
The issue here is .find() returns undefined once there is no fulfillment for the condition:
The value of the first element in the array that satisfies the provided testing function. Otherwise, undefined is returned.
So probably you can use || operator to check if you have any value returned from .find() or you can replace with empty object {} instead on the right side of the operator.
Probably the option for one-liner is the following:
const myArray = [
{ id: 12 },
{ id: 13 },
{ id: 14 }
];
const { id } = myArray.find(e => e.id === 17) || {};
console.log(id);
So you can destructure id property even if it returned undefined in this way.
Also if you need you can add default value to your destructuring statement based on the documentation which states for Destructuring statement as follows:
A variable can be assigned a default, in the case that the value unpacked from the object is undefined.
const { id = 10 } = {};
console.log(id);
I hope this helps!

Check if properties in TypeScript Object are empty

I have an object that looks like this:
protected products: {
color: string[],
brand: number[],
} = {};
I want to check if the properties of products are null (simply Array(0)). How can I do it?
I am using "target": "es2015".
You could probably use lodash _.isEmpty(value):
_.isEmpty(null);
// => true
_.isEmpty(true);
// => true
_.isEmpty(1);
// => true
_.isEmpty([1, 2, 3]);
// => false
_.isEmpty({ 'a': 1 });
// => false
Could try this:
const checkEmptyObj = (object) => {
// gets an array of the values for each kv pair in your object
const values = Object.values(object);
// if you add kv pairs with non array types, will have to adjust this
// removes all zero length arrays (or strings) from values array
const nonEmptyValues = values.filter(value => value.length > 0)
// if any items are in the nonEmptyValues array, return false
return nonEmptyValues.length < 1
}
This is not a catch all solution, it needs more work for use beyond your stated case. Specifically, it only works on objects of one level deep. If you are passing in a nested object, you'll have to adjust the function to be recursive. If you expect to have other data types, you will have to do some handling of those inside the filter function (the .length call will fail on numbers and objects, among others).
After more thought, I like this solution more.
return values.every(value => value.length === 0)
For checking if all the arrays are empty, you can approach it as follow:
This is assuming that all values are arrays
let products = {color: [],brand: []};
let allEmpty = Object.values(products).every(({length}) => !Boolean(length));
console.log(allEmpty);
As the argument is an array, we can use the destructuring assignment as follow:
{length} // Basically to extract the attribute length
The number 0 is considered falsy, so we can do explicit type coercion (or type casting) on values as follow:
!Boolean(length) // Coerce to boolean the number from arr.length
// The negation is needed because if the length === 0 that
// means the array is empty, so we want the result
// as true in our handler for the function every

Why does dot notation returns object with added properties while spread operator does not?

I have a function that returns a new object based on conditions. Why does when I use the dot notation it returns the new object while spread operator does not
This line returns the new object with new property
const newValue = values => {
const condition = "SUCCESS"
const result = values.filter(r => {
if(condition === "SUCCESS"){
r.codes = "Success Test"
return r
}
r.codes = "Fail Test"
return r
})
return result
}
This line returns the old object without the new property
const newValue = values => {
const condition = "SUCCESS"
const result = values.filter(r => {
if(condition === "SUCCESS"){
return { ...r, codes: "Success Test" }
}
return { ...r, codes: "Fail Test" }
})
return result
}
Expected result should be :
result = [{ name:"Hey", codes:"Success Test" }]
filter only cares if the function you pass to it returns a value that (can be coerced to something that) is true or false.
In both cases, you return an object. Objects are always true values, so the value in the original array is kept in the filtered array.
In your first example, the object you return is the original object which you modify.
In your second example, the object you return is a new object, so the original object is unmodified. Since filter only cases about true or false, it always returns the original object (which will only have a new property on it if you modify the original).
You always return a true value, and never return a false value, which makes using filter pointless.
It looks like you are trying to map the array, not filter it.
The .filter callback is meant to take an array, and create a new array which is the same as the old array, except with items removed based on a condition. Here, you're using .filter incorrectly, since you're both mutating the existing array items (with r.codes = assignments) and you're always returning an object from the .filter callback (and objects are always truthy, so every item in the original array will be present in the output array).
Because assigning to r.codes mutates the existing array, and because result will always be the original array (with the mutated items), assigning to r.codes results in a changed array.
When you spread into a new returned object, that object is checked for its truthyness (objects are truthy), and then discarded; the object is not used anywhere else.
If you want to mutate the existing objects, use forEach (which is the proper array method to use for side-effects only):
const newValue = values => {
const condition = "SUCCESS"
values.forEach(value => {
value.codes = condition === "SUCCESS" ? "Success Test" : 'Fail Test';
});
return values;
}
If you don't want to mutate the existing objects, use .map and spread:
const newValue = values => {
const condition = "SUCCESS"
return values.map(value => ({
...value,
codes: condition === "SUCCESS" ? "Success Test" : 'Fail Test'
}));
}

javascript object hash vs lodash foreach in lodash remove

I'm trying to delete some data from a complex object.
The format of the original data is as follows.
let originData =
[
{
name : exampleDepth1,
depth1Data :
[
{
name : exampleDepth2,
depth2Data :
[
{
code: 1234///will be delete from that data
},
...
]
},
...
]
},
....
]
let willbeDeletecode = [ 3, 100, 1234, 1000];
The name of the array to be deleted is the code value in the depth2Data array of originData, The name of the array to delete is willbeDeletecode.
I'm sorry if you were uncomfortable.
I'm trying to erase it in two ways.
let deleteBook = {}
_.forEach(willbeDeletecode, (deleteCode) => {
deleteBook[`${deleteCode}`] = deleteCode;
})
_.remove(originData, (depth1) => {
_.remove(depth1.depth1Data, (depth2) => {
/*
// delete with object hash
_.remove(depth2.depth2Data, (eachDepth2Data) => {
return deleteBook[eachDepth2Data.code] === undefined
})
*/
/*
// delete with forEach
let ret = false;
_.remove(depth2.depth2Data, (eachDepth2Data) => {
_.forEach(willbeDeletecode, (deleteCode) => {
if(deleteCode === eachDepth2Data.code){
ret = true;
return false;
}
})
return ret
})
*/
return depth2.depth2Data.length === 0;
})
return depth1.depth1Data.length === 0;
})
I have two separate ways of annotating each one.
The first is to create an object(deleteBook) and insert the data of willbeDeletecode and use it in remove of lodash.
The second method is entirely a comparison of all through the forEach function.
The above method was repeated 1000 times to benchmark. As a result, the first method is 100 ~ 200ms and the second method is 500 ~ 700ms.
Of course, the willbeDeletecode is around 10 or so, but I thought Object hash was faster. But the result was the opposite.
If there are more variables in willbeDeletecode, will there be another conclusion? I want know why this results.
The object hash is to be preferred. You could also use an ES6 Set for such purpose.
Such a hash solution should be faster.
One reason that you did not see this in your case, is that the first variant of your code removes the opposite of what it should. The _remove callback should return a truthy value when the corresponding item should be removed, yet your code returns true when the value is not in the codes that should be deleted. You should use a !== comparison:
_.remove(depth2.depth2Data, (eachDepth2Data) => {
return deleteBook[eachDepth2Data.code] !== undefined
})
As you had a === there, you probably had a lot more removals going on, giving a longer time of execution.

Categories

Resources