Check if an object is empty and with undefined properties - javascript

I'm trying to check the below,
USECASE: 1
var obj = {};
_.isEmpty(obj); ====> returns true
USECASE: 2
var obj = { model: undefined, vendor: undefined, type: undefined }
_.isEmpty(obj); ====> returns false
In usecase 2 is there any other function that i could leverage to return true since all the properties are undefined.
I referred this http://www.ericfeminella.com/blog/2012/08/18/determining-if-an-object-is-empty-with-underscore-lo-dash/ but not sure how to implement it without modifying the native method.

Without Underscore:
const objEmpty = obj => Object.keys(obj).every(key => obj[key] === undefined);
Will accept an object and return true if the object is empty (no properties) or if all the properties have undefined value. Else returns false.

You could use every and pass in the isUndefined predicate:
var obj = { model: undefined, vendor: undefined, type: undefined }
var result = _.every(obj, _.isUndefined);
Alternatively you could omit the undefined values and check whether the object is empty:
var result = _.isEmpty(_.omit(obj, _.isUndefined));

Related

Undefined vs Empty String - Javascript with example

I am trying to find the first processed === true and return the value.
My works seems to work but if there are no processed the code turns undefined instead of <empty string>
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
const myValue = values.reduce((acc, curr) => {
if (curr.primary) {
return curr.value.toLowerCase();
}
}, '');
console.log("My Value: " + myValue);
What am I missing here?
reduce calls the callback function once for each item in the loop.
curr is the current value. acc is the return value from the previous function (or the second argument ('') the first time going around the loop.
Your code completely ignores acc so the value returned by reduce depends entirely on the last value in the array.
Your function tests that value with curr.primary. If that is a true value it return curr.value.toLowerCase(). If it isn't a true value, then it gets to the end of the function without hitting a return statement. Any function that doesn't return will return undefined.
To find the first value that matches a condition, use find not reduce.
Then do a test to use an empty string if you didn't find anything.
const match = values.find(value => value.primary === true);
const myValue = match?.value.toLowerCase() ?? "";
I am trying to find the first processed === true and return the value [else an empty string ""].
You can use Array.prototype.find() with the optional chaining operator (?.) along with the nullish coalescing operator (??) in the case that no value is found:
const array1 = [
{ value: 'bar', processed: false },
{ value: 'foo', processed: false },
];
const myValue1 = array1.find(o => o.processed)?.value.toLowerCase() ?? '';
console.log('myValue1:', myValue1); // "myValue1:" ""
console.log('type:', typeof myValue1); // "type:" "string"
const array2 = [
{ value: 'BAR', processed: false },
{ value: 'FOO', processed: true },
];
const myValue2 = array2.find(o => o.processed)?.value.toLowerCase() ?? '';
console.log('myValue2:', myValue2); // "myValue2:" "foo"
console.log('type:', typeof myValue2); // "type:" "string"
Here's a breakdown of the syntax evaluation for the first value:
const myValue1 = array1.find(o => o.processed)?.value.toLowerCase() ?? '';
// 11111111111111111111111111111 22222222222222222222 44 55
// 33333333333333333333333333333333333333333333333333
// 1. This evaluates to undefined
// 2. So this part is not evaluated, and...
// 3. the entire left side evaluates to undefined
// 4. Because 3 is nullable (null or undefined), when the ?? operator executes...
// 5. the left side (3) is ignored, and the right side (5) becomes the value
In contrast with the value computed from the second array:
const myValue2 = array2.find(o => o.processed)?.value.toLowerCase() ?? '';
// 11111111111111111111111111111 22222233333333333333 55 66
// 44444444444444444444444444444444444444444444444444
// 1. This evaluates to { value: 'FOO', processed: true }
// 2. So this part is evaluated to "FOO"
// 3. which becomes "foo", and...
// 4. the entire left side evaluates to "foo"
// 5. Because 4 is NOT nullable (null or undefined), when the ?? operator executes...
// 6. the left side (4) becomes the final value, and the right side (6) is ignored
To find the first element that meets a condition you should use find method.
Reduce will run on the entire array even after that condition is met since it's purpose is to reduce an entire array into a different data structure (i.e string/object). Find method will exit as soon as an item that meets the condition is found (or after checking the entire array if non of the items does)
As to replacing undefined with an empty string, in the attached snippet I used a or condition (although some would prefer conditional operator), since undefined is falsey, it will insert the empty string.
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
const myValue = values.find(curr => curr.process);
console.log("My Value: " + (myValue?.value?.toLowerCase() || ''));
Best of luck with your project:)
This should be all:
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
const myValue = values.reduce((acc, curr) => curr.process ? curr.value.toLowerCase() : '', '');
console.log("My Value: " + myValue);
you might be better off using a foreach loop to accomplish what you are trying to do:
const values = [{
value: "bar",
process: false
},
{
value: "foo",
process: false
}
];
var processedValue = '';
values.forEach(element => {
if(element.process && !processedValue)
processedValue = element.value;
});
console.log(processedValue);

Delete an object within an outer object not working

Currently trying to delete an object within another object using the delete keyword as I've seen all around the web. The object I'm using is similar to the one below:
object = { NAME: {hello: 3838383, goodbye: 3474737}, NAME2: {hello: 3838383, goodbye: 3474737} }
Trying:
delete object.NAME
But I continually get: Cannot delete property 'NAME' of [object Object]. Any ideas?
It sounds like NAME is a non-configurable property. That means you can't delete it I'm afraid, as deleting (removing) a property counts as "configuring" it (as does changing the configurable flag on the property).
You can see what the configuration of the property is by using Object.getOwnPropertyDescriptor. In your case it probably will either not show a configurable property at all (because false is the default) or more likely it'll show configurable: false.
Here's an example which shows using getOwnPropertyDescriptor and demonstrates the error you're getting:
"use strict";
const object = { };
Object.defineProperty(object, "NAME", {
value: {hello: 3838383, goodbye: 3474737},
configurable: false,
writable: true
});
console.log(Object.getOwnPropertyDescriptor(object, "NAME"));
delete object.NAME;
If the property is writable, you can assign some other value to itm, such as null or undefined:
object.NAME = null;
But if it's also non-writable, you can't do that, either.
As a final resort, you could create a new object and only copy the properties to it that you want, and assign that new object to the variable or property you're using to refer to the object. For instance:
object = Object.fromEntries(
Object.entries(object)
.filter(([key]) => key !== "NAME")
);
Live Example:
"use strict";
let object = {
NAME2: {hello: 3838383, goodbye: 3474737}
};
Object.defineProperty(object, "NAME", {
value: {hello: 3838383, goodbye: 3474737},
configurable: false, // Just here for emphasis, false is the default
writable: false // same
});
console.log(Object.getOwnPropertyDescriptor(object, "NAME"));
// Can't do this: delete object.NAME;
object = Object.fromEntries(
Object.entries(object)
.filter(([key]) => key !== "NAME")
);
console.log(object);
.as-console-wrapper {
max-height: 100% !important;
}

Using forEach in an array to find an object and change it's value in TypeScript

I have a statement like so:
private updateVariable(anId:number): void {
this.model.forEach(q =>
{
q.anId === anId && (q.isUpdated = !q.isUpdated)
});
The model is defined as:
private model:Array<IMyData> = [];
Also IMyData is defined with this:
export interface IMyData{
anId:number;
isUpdated:boolean;
}
The goal is to iterate over the data to find the matching anId and:
change isUpdated from:
null and false to true
and from:
true to false
Thanks in advance.
You can do it in 1 line instead. Using Array's .map()
const anId = '123';
this.model = this.model.map(item => item.anId === anId ? {...item, isUpdated: !item.isUpdated} : item)
console.log(this.model); // to check the array with it's updated data

destructure object only if it's truthy

Suppose I want to destructure my function argument like this
const func = ({field: {subField}}) => subField;
How can I prevent this from throwing an error if field is undefined or null ?
You might use a default value:
const func = ({field: {subField} = {}}) => subField;
It works only with {field: undefined} though, not with null as a value. For that I'd just use
const func = ({field}) => field == null ? null : field.subField;
// or if you don't care about getting both null or undefined respectively
const func = ({field}) => field && field.subField;
See also javascript test for existence of nested object key for general solutions.
You could only part destruction and use for subField a parameter with a check.
var fn = ({ field }, subField = field && field.subField) => subField;
console.log(fn({ field: null }));
A good way to fix both the cases of null and undefined is the following
const func = ({field}) => {
let subField = null;
if(field) {
({subField} = field);
}
return subField
};
If you only want to handle the case when field is undefined, you could just to
const func = ({field: {subField} = {}}) => subField;
whereby if field is undefined the default empty object is used as its value

How to change the way to access property in an object?

The task is to change the way to access a property on an object and change the dot operator to a function that will have two arguments: an object and a property.
var exObject = {
arr: [],
obj: {},
str: 'string',
num: 22,
boolean: false,
undeFined: undefined,
nullValue: null
}
for example: typeof change(exObject, "str") should result in string;
function change(obj,property){
var prop="";
for (var key in obj){
if ([key]==property){
prop=obj[key].constructor;
}
}
return prop;
}
My code is clearly wrong - would be happy about any suggestions!
If I understand maybe this will work for you
function chang(obj, property){
if(obj.hasOwnProperty(property)){
return obj[property];
}
return null;
}
PS: the property needs to be a string, such as 'arr'

Categories