Can Javascript spread operator include undefined fields of an object? - javascript

Is there a more readable way of spreading undefined fields of an object on another object without traversing every element of it?
Following example spreads object A on object B:
let A = { f1:'Foo', f2:'Bar', f3:'Baz' }
let B = { ...A }
// Now B has the value of { f1:'Foo', f2:'Bar', f3:'Baz' }
However in the following example spread operator will not include undefined values:
let A = { f1:'Foo', f2:undefined, f3:'Baz' }
let B = { ...A }
// Now B has the value of { f1:'Foo', f3:'Baz' }
// I would like it to be spread like { f1:'Foo', f2:undefined, f3:'Baz' }
// or { f1:'Foo', f2:null, f3:'Baz' }
Is there a way of projecting fields with undefined value using spread operator? (and obviously WITHOUT traversing every field of the object A and spreading into B if the value of that field is not undefined)

If you're asking if the spread operator will maintain undefined property values 'post spread', they do.
const original = { one: 1, two: 2, three: undefined, four: null };
console.log(original);
const withSpread = {five: 5, ...original };
console.log(withSpread);
console.log(typeof withSpread.three === 'undefined')
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

It turned out to be an invalid assertion of mine. Spread operator indeed spreads fields with undefined value. It was JSON.stringify() removing those fields within one of my sources, which lead me to an invalid assertion.
For Express.js users; you can use app.set('json replacer', (k, v) => v===undefined ? null : v); to let express stringify your json response by replacing undefined values with null
Or likewise, you can use JSON.stringify({...}, (k, v) => v===undefined ? null : v) to let it stringify by replacing undefined values with null

Related

Counting instances of values in an object using Array.prototype.reduce()

Here's an MDN example of Array.prototype.reduce() I'm not quite understand:
const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];
const countedNames = names.reduce((allNames, name) => {
const currCount = allNames[name] ?? 0;
return {
...allNames,
[name]: currCount + 1,
};
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
What does allNames[name] mean in here? is this a array [attribute] syntax? I only known array[index], could you let me know the name of this form?
And why here's another {} at the end of below sentence:
return{...allNames,[name]: currCount + 1,};}, {})
Thank you!
const currCount = allNames[name] ?? 0
This is a use of the Nullish coalescing operator. It means that the variable currCount will first try to be assigned the value of allNames[name]. However, if that results in a "nullish" value (in this case undefined because there hasn't been anything assigned in allNames for a specific name), then the variable gets assigned to 0.
return {
...allNames,
};
This is a use of the spread operator and object destructuring. It means that the a new object will be created with all the properties (keys and values) of the old allNames object.
[name]: currCount + 1,
This part says to create a new property with the key as a specific name and the value as the current count plus one. Combined with the snippet above, this will create a new object that's the same as allNames, except that the property with the key name will get overwritten, with the new value having an updated count.
The (??) is called a Nullish coalescing operator.
According to MDN, it is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, and otherwise returns its left-hand side operand.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing
So allNames[name] ?? 0 is saying, "Return the value of allNames[name], but if it is null or undefined, return 0 instead.
It is similar to the Ternary Operator (?), but it's more terse.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
const allNames = [];
let currCount = allNames[name] ?? 0;
console.log(currCount);
currCount = (allNames[name]) ? allNames[name] : 0;
console.log(currCount);
It is also kind of similar to the Logical Disjuncton Operator or Double Pipes ( || ). This one returns the value of one of the specified operands.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR
It is often used to set a default value and is used like:
const allNames = [];
const value = allNames[name] || 0;
console.log(value)
The (...) is called Spread Syntax. It allows an iterable, such as an array or string, to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected.
In addition to what other answers have said, It's handy when you don't want to define a gazillion arguments for a function, or you don't know how many arguments are comming, or you don't know what is being passed to a callback.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
Here's an example:
function callback(...args) {
console.log(args);
}
document.addEventListener('DOMContentLoaded', (event) => callback(event, 'foo'));
?? Nullish Coalescing Operator Often used to fallback to a default value if the left-hand-side operand is null or undefined
... Spread syntax Used to (in your case) reinsert, spread an object properties and values into another object. Important to know is that the properties that follow that spread will override the previous properties values!
Your .reduce() function function "reduces" (converts) the input Array into an Object {} (— that thing (second argument AKA: currentValue) you noticed at the end of reduce's }, {});).
Since that currentValue object {} initially has no properties (it's "empty") you cannot increment a value to a non-existing property.
In the first iteration allNames[name] (being allNames["Alice"]) is undefined since there's no "Alice" property (AKA: key) in allNames. Therefore, you cannot increment something that is undefined (not an integer).
const currCount = allNames[name] ?? 0;
if allNames[name] returns undefined — the Nullish coalescing operator ?? will make sure to fallback to the value of 0 - and stores it into currCount.
return {
...allNames,
[name]: currCount + 1,
};
The above just (uselessly!) spreads ... the ...allNames object into a new Object return {} (that is then returned and reused in the next iteration as a modified allNames) - and increments the number of a specific property name (being the currently iterated person's name).
Then overrides (by using [name]: currCount + 1,) any existing [name] property to an incremented value.
This spreading syntax is just a shorthand of Object.assign().
Here's an example:
const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];
const countedNames = names.reduce((allNames, name) => {
const currCount = allNames[name] ?? 0;
return Object.assign({}, allNames, {[name]: currCount + 1});
}, {});
console.log(countedNames)
Here's a different (better, more legible) remake of the same:
const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];
const countedNames = names.reduce((ob, name) => {
ob[name] ??= 0; // if undefined, set that property and set value to 0
ob[name] += 1; // Increment value by 1
return ob;
}, {});
console.log(countedNames)
Which without using any fancy code is the same as doing:
const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];
const countedNames = names.reduce((ob, name) => {
if (!ob.hasOwnProperty(name)) {
ob[name] = 0;
}
ob[name] += 1; // Increment it
return ob;
}, {});
console.log(countedNames)
which, without the .reduce() it's done like:
const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];
const countedNames = {};
names.forEach((name) => {
if (!countedNames.hasOwnProperty(name)) { // If object has no such name, create it and assign value to 0
countedNames[name] = 0;
}
countedNames[name] += 1; // Increment the value by 1
});
console.log(countedNames);

How can I check if there is variable in json object [duplicate]

How do I check if a particular key exists in a JavaScript object or array?
If a key doesn't exist, and I try to access it, will it return false? Or throw an error?
Checking for undefined-ness is not an accurate way of testing whether a key exists. What if the key exists but the value is actually undefined?
var obj = { key: undefined };
console.log(obj["key"] !== undefined); // false, but the key exists!
You should instead use the in operator:
var obj = { key: undefined };
console.log("key" in obj); // true, regardless of the actual value
If you want to check if a key doesn't exist, remember to use parenthesis:
var obj = { not_key: undefined };
console.log(!("key" in obj)); // true if "key" doesn't exist in object
console.log(!"key" in obj); // Do not do this! It is equivalent to "false in obj"
Or, if you want to particularly test for properties of the object instance (and not inherited properties), use hasOwnProperty:
var obj = { key: undefined };
console.log(obj.hasOwnProperty("key")); // true
For performance comparison between the methods that are in, hasOwnProperty and key is undefined, see this benchmark:
Quick Answer
How do I check if a particular key exists in a JavaScript object or array?
If a key doesn't exist and I try to access it, will it return false? Or throw an error?
Accessing directly a missing property using (associative) array style or object style will return an undefined constant.
The slow and reliable in operator and hasOwnProperty method
As people have already mentioned here, you could have an object with a property associated with an "undefined" constant.
var bizzareObj = {valid_key: undefined};
In that case, you will have to use hasOwnProperty or in operator to know if the key is really there. But, but at what price?
so, I tell you...
in operator and hasOwnProperty are "methods" that use the Property Descriptor mechanism in Javascript (similar to Java reflection in the Java language).
http://www.ecma-international.org/ecma-262/5.1/#sec-8.10
The Property Descriptor type is used to explain the manipulation and reification of named property attributes. Values of the Property Descriptor type are records composed of named fields where each field’s name is an attribute name and its value is a corresponding attribute value as specified in 8.6.1. In addition, any field may be present or absent.
On the other hand, calling an object method or key will use Javascript [[Get]] mechanism. That is a far way faster!
Benchmark
https://jsben.ch/HaHQt
.
Using in operator
var result = "Impression" in array;
The result was
12,931,832 ±0.21% ops/sec 92% slower
Using hasOwnProperty
var result = array.hasOwnProperty("Impression")
The result was
16,021,758 ±0.45% ops/sec 91% slower
Accessing elements directly (brackets style)
var result = array["Impression"] === undefined
The result was
168,270,439 ±0.13 ops/sec 0.02% slower
Accessing elements directly (object style)
var result = array.Impression === undefined;
The result was
168,303,172 ±0.20% fastest
EDIT: What is the reason to assign to a property the undefined value?
That question puzzles me. In Javascript, there are at least two references for absent objects to avoid problems like this: null and undefined.
null is the primitive value that represents the intentional absence of any object value, or in short terms, the confirmed lack of value. On the other hand, undefined is an unknown value (not defined). If there is a property that will be used later with a proper value consider use null reference instead of undefined because in the initial moment the property is confirmed to lack value.
Compare:
var a = {1: null};
console.log(a[1] === undefined); // output: false. I know the value at position 1 of a[] is absent and this was by design, i.e.: the value is defined.
console.log(a[0] === undefined); // output: true. I cannot say anything about a[0] value. In this case, the key 0 was not in a[].
Advice
Avoid objects with undefined values. Check directly whenever possible and use null to initialize property values. Otherwise, use the slow in operator or hasOwnProperty() method.
EDIT: 12/04/2018 - NOT RELEVANT ANYMORE
As people have commented, modern versions of the Javascript engines (with firefox exception) have changed the approach for access properties. The current implementation is slower than the previous one for this particular case but the difference between access key and object is neglectable.
It will return undefined.
var aa = {hello: "world"};
alert( aa["hello"] ); // popup box with "world"
alert( aa["goodbye"] ); // popup box with "undefined"
undefined is a special constant value. So you can say, e.g.
// note the three equal signs so that null won't be equal to undefined
if( aa["goodbye"] === undefined ) {
// do something
}
This is probably the best way to check for missing keys. However, as is pointed out in a comment below, it's theoretically possible that you'd want to have the actual value be undefined. I've never needed to do this and can't think of a reason offhand why I'd ever want to, but just for the sake of completeness, you can use the in operator
// this works even if you have {"goodbye": undefined}
if( "goodbye" in aa ) {
// do something
}
"key" in obj
Is likely testing only object attribute values that are very different from array keys
Checking for properties of the object including inherited properties
Could be determined using the in operator which returns true if the specified property is in the specified object or its prototype chain, false otherwise
const person = { name: 'dan' };
console.log('name' in person); // true
console.log('age' in person); // false
Checking for properties of the object instance (not including inherited properties)
*2021 - Using the new method ***Object.hasOwn() as a replacement for Object.hasOwnProperty()
Object.hasOwn() is intended as a replacement for Object.hasOwnProperty() and is a new method available to use (yet still not fully supported by all browsers like safari yet but soon will be)
Object.hasOwn() is a static method which returns true if the specified object has the specified property as its own property. If the property is inherited, or does not exist, the method returns false.
const person = { name: 'dan' };
console.log(Object.hasOwn(person, 'name'));// true
console.log(Object.hasOwn(person, 'age'));// false
const person2 = Object.create({gender: 'male'});
console.log(Object.hasOwn(person2, 'gender'));// false
What is the motivation to use it over Object.prototype.hasOwnProperty? - It is recommended to this method use over the Object.hasOwnProperty() because it also works for objects created by using Object.create(null) and for objects that have overridden the inherited hasOwnProperty() method. Although it's possible to solve these kind of problems by calling Object.prototype.hasOwnProperty() on an external object, Object.hasOwn() overcome these problems, hence is preferred (see examples below)
let person = {
hasOwnProperty: function() {
return false;
},
age: 35
};
if (Object.hasOwn(person, 'age')) {
console.log(person.age); // true - the remplementation of hasOwnProperty() did not affect the Object
}
let person = Object.create(null);
person.age = 35;
if (Object.hasOwn(person, 'age')) {
console.log(person.age); // true - works regardless of how the object was created
}
More about Object.hasOwn can be found here : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn
Browser compatibility for Object.hasOwn - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn#browser_compatibility
The accepted answer refers to Object. Beware using the in operator on Array to find data instead of keys:
("true" in ["true", "false"])
// -> false (Because the keys of the above Array are actually 0 and 1)
To test existing elements in an Array: Best way to find if an item is in a JavaScript array?
Three ways to check if a property is present in a javascript object:
!!obj.theProperty
Will convert value to bool. returns true for all but the false value
'theProperty' in obj
Will return true if the property exists, no matter its value (even empty)
obj.hasOwnProperty('theProperty')
Does not check the prototype chain. (since all objects have the toString method, 1 and 2 will return true on it, while 3 can return false on it.)
Reference:
http://book.mixu.net/node/ch5.html
If you are using underscore.js library then object/array operations become simple.
In your case _.has method can be used. Example:
yourArray = {age: "10"}
_.has(yourArray, "age")
returns true
But,
_.has(yourArray, "invalidKey")
returns false
Answer:
if ("key" in myObj)
{
console.log("key exists!");
}
else
{
console.log("key doesn't exist!");
}
Explanation:
The in operator will check if the key exists in the object. If you checked if the value was undefined: if (myObj["key"] === 'undefined'), you could run into problems because a key could possibly exist in your object with the undefined value.
For that reason, it is much better practice to first use the in operator and then compare the value that is inside the key once you already know it exists.
Here's a helper function I find quite useful
This keyExists(key, search) can be used to easily lookup a key within objects or arrays!
Just pass it the key you want to find, and search obj (the object or array) you want to find it in.
function keyExists(key, search) {
if (!search || (search.constructor !== Array && search.constructor !== Object)) {
return false;
}
for (var i = 0; i < search.length; i++) {
if (search[i] === key) {
return true;
}
}
return key in search;
}
// How to use it:
// Searching for keys in Arrays
console.log(keyExists('apple', ['apple', 'banana', 'orange'])); // true
console.log(keyExists('fruit', ['apple', 'banana', 'orange'])); // false
// Searching for keys in Objects
console.log(keyExists('age', {'name': 'Bill', 'age': 29 })); // true
console.log(keyExists('title', {'name': 'Jason', 'age': 29 })); // false
It's been pretty reliable and works well cross-browser.
vanila js
yourObjName.hasOwnProperty(key) : true ? false;
If you want to check if the object has at least one property in es2015
Object.keys(yourObjName).length : true ? false
ES6 solution
using Array#some and Object.keys. It will return true if given key exists in the object or false if it doesn't.
var obj = {foo: 'one', bar: 'two'};
function isKeyInObject(obj, key) {
var res = Object.keys(obj).some(v => v == key);
console.log(res);
}
isKeyInObject(obj, 'foo');
isKeyInObject(obj, 'something');
One-line example.
console.log(Object.keys({foo: 'one', bar: 'two'}).some(v => v == 'foo'));
Optional chaining operator:
const invoice = {customer: {address: {city: "foo"}}}
console.log( invoice?.customer?.address?.city )
console.log( invoice?.customer?.address?.street )
console.log( invoice?.xyz?.address?.city )
See supported browsers list
For those which have lodash included in their project:There is a lodash _.get method which tries to get "deep" keys:
Gets the value at path of object. If the resolved value is undefined,
the defaultValue is returned in its place.
var object = { 'a': [{ 'b': { 'c': 3 } }] };
console.log(
_.get(object, 'a[0].b.c'), // => 3
_.get(object, ['a', '0', 'b', 'c']), // => 3
_.get(object, 'a.b.c'), // => undefined
_.get(object, 'a.b.c', 'default') // => 'default'
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
This will effectively check if that key, however deep, is defined and will not throw an error which might harm the flow of your program if that key is not defined.
To find if a key exists in an object, use
Object.keys(obj).includes(key)
The ES7 includes method checks if an Array includes an item or not, & is a simpler alternative to indexOf.
The easiest way to check is
"key" in object
for example:
var obj = {
a: 1,
b: 2,
}
"a" in obj // true
"c" in obj // false
Return value as true implies that key exists in the object.
Optional Chaining (?.) operator can also be used for this
Source: MDN/Operators/Optional_chaining
const adventurer = {
name: 'Alice',
cat: {
name: 'Dinah'
}
}
console.log(adventurer.dog?.name) // undefined
console.log(adventurer.cat?.name) // Dinah
An alternate approach using "Reflect"
As per MDN
Reflect is a built-in object that provides methods for interceptable
JavaScript operations.
The static Reflect.has() method works like the in operator as a
function.
var obj = {
a: undefined,
b: 1,
c: "hello world"
}
console.log(Reflect.has(obj, 'a'))
console.log(Reflect.has(obj, 'b'))
console.log(Reflect.has(obj, 'c'))
console.log(Reflect.has(obj, 'd'))
Should I use it ?
It depends.
Reflect.has() is slower than the other methods mentioned on the accepted answer (as per my benchmark test). But, if you are using it only a few times in your code, I don't see much issues with this approach.
We can use - hasOwnProperty.call(obj, key);
The underscore.js way -
if(_.has(this.options, 'login')){
//key 'login' exists in this.options
}
_.has = function(obj, key) {
return hasOwnProperty.call(obj, key);
};
If you want to check for any key at any depth on an object and account for falsey values consider this line for a utility function:
var keyExistsOn = (o, k) => k.split(".").reduce((a, c) => a.hasOwnProperty(c) ? a[c] || 1 : false, Object.assign({}, o)) === false ? false : true;
Results
var obj = {
test: "",
locals: {
test: "",
test2: false,
test3: NaN,
test4: 0,
test5: undefined,
auth: {
user: "hw"
}
}
}
keyExistsOn(obj, "")
> false
keyExistsOn(obj, "locals.test")
> true
keyExistsOn(obj, "locals.test2")
> true
keyExistsOn(obj, "locals.test3")
> true
keyExistsOn(obj, "locals.test4")
> true
keyExistsOn(obj, "locals.test5")
> true
keyExistsOn(obj, "sdsdf")
false
keyExistsOn(obj, "sdsdf.rtsd")
false
keyExistsOn(obj, "sdsdf.234d")
false
keyExistsOn(obj, "2134.sdsdf.234d")
false
keyExistsOn(obj, "locals")
true
keyExistsOn(obj, "locals.")
false
keyExistsOn(obj, "locals.auth")
true
keyExistsOn(obj, "locals.autht")
false
keyExistsOn(obj, "locals.auth.")
false
keyExistsOn(obj, "locals.auth.user")
true
keyExistsOn(obj, "locals.auth.userr")
false
keyExistsOn(obj, "locals.auth.user.")
false
keyExistsOn(obj, "locals.auth.user")
true
Also see this NPM package: https://www.npmjs.com/package/has-deep-value
While this doesn't necessarily check if a key exists, it does check for the truthiness of a value. Which undefined and null fall under.
Boolean(obj.foo)
This solution works best for me because I use typescript, and using strings like so 'foo' in obj or obj.hasOwnProperty('foo')
to check whether a key exists or not does not provide me with intellisense.
const object1 = {
a: 'something',
b: 'something',
c: 'something'
};
const key = 's';
// Object.keys(object1) will return array of the object keys ['a', 'b', 'c']
Object.keys(object1).indexOf(key) === -1 ? 'the key is not there' : 'yep the key is exist';
In 'array' world we can look on indexes as some kind of keys. What is surprising the in operator (which is good choice for object) also works with arrays. The returned value for non-existed key is undefined
let arr = ["a","b","c"]; // we have indexes: 0,1,2
delete arr[1]; // set 'empty' at index 1
arr.pop(); // remove last item
console.log(0 in arr, arr[0]);
console.log(1 in arr, arr[1]);
console.log(2 in arr, arr[2]);
Worth noting that since the introduction of ES11 you can use the nullish coalescing operator, which simplifies things a lot:
const obj = {foo: 'one', bar: 'two'};
const result = obj.foo ?? "Not found";
The code above will return "Not found" for any "falsy" values in foo. Otherwise it will return obj.foo.
See Combining with the nullish coalescing operator
JS Double Exclamation !! sign may help in this case.
const cars = {
petrol:{
price: 5000
},
gas:{
price:8000
}
}
Suppose we have the object above and If you try to log car with petrol price.
=> console.log(cars.petrol.price);
=> 5000
You'll definitely get 5000 out of it. But what if you try to get an
electric car which does not exist then you'll get undefine
=> console.log(cars.electric);
=> undefine
But using !! which is its short way to cast a variable to be a
Boolean (true or false) value.
=> console.log(!!cars.electric);
=> false
In my case, I wanted to check an NLP metadata returned by LUIS which is an object. I wanted to check if a key which is a string "FinancialRiskIntent" exists as a key inside that metadata object.
I tried to target the nested object I needed to check -> data.meta.prediction.intents (for my own purposes only, yours could be any object)
I used below code to check if the key exists:
const hasKey = 'FinancialRiskIntent' in data.meta.prediction.intents;
if(hasKey) {
console.log('The key exists.');
}
else {
console.log('The key does not exist.');
}
This is checking for a specific key which I was initially looking for.
Hope this bit helps someone.
yourArray.indexOf(yourArrayKeyName) > -1
fruit = ['apple', 'grapes', 'banana']
fruit.indexOf('apple') > -1
true
fruit = ['apple', 'grapes', 'banana']
fruit.indexOf('apple1') > -1
false
for strict object keys checking:
const object1 = {};
object1.stackoverflow = 51;
console.log(object1.hasOwnProperty('stackoverflow'));
output: true
These example can demonstrate the differences between defferent ways. Hope it will help you to pick the right one for your needs:
// Lets create object `a` using create function `A`
function A(){};
A.prototype.onProtDef=2;
A.prototype.onProtUndef=undefined;
var a=new A();
a.ownProp = 3;
a.ownPropUndef = undefined;
// Let's try different methods:
a.onProtDef; // 2
a.onProtUndef; // undefined
a.ownProp; // 3
a.ownPropUndef; // undefined
a.whatEver; // undefined
a.valueOf; // ƒ valueOf() { [native code] }
a.hasOwnProperty('onProtDef'); // false
a.hasOwnProperty('onProtUndef'); // false
a.hasOwnProperty('ownProp'); // true
a.hasOwnProperty('ownPropUndef'); // true
a.hasOwnProperty('whatEver'); // false
a.hasOwnProperty('valueOf'); // false
'onProtDef' in a; // true
'onProtUndef' in a; // true
'ownProp' in a; // true
'ownPropUndef' in a; // true
'whatEver' in a; // false
'valueOf' in a; // true (on the prototype chain - Object.valueOf)
Object.keys(a); // ["ownProp", "ownPropUndef"]
const rawObject = {};
rawObject.propertyKey = 'somethingValue';
console.log(rawObject.hasOwnProperty('somethingValue'));
// expected output: true
checking particular key present in given object, hasOwnProperty will works here.
If you have ESLint configured in your project follows ESLint rule no-prototype-builtins. The reason why has been described in the following link:
// bad
console.log(object.hasOwnProperty(key));
// good
console.log(Object.prototype.hasOwnProperty.call(object, key));
// best
const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
console.log(has.call(object, key));
/* or */
import has from 'has'; // https://www.npmjs.com/package/has
console.log(has(object, key));
New awesome solution with JavaScript Destructuring:
let obj = {
"key1": "value1",
"key2": "value2",
"key3": "value3",
};
let {key1, key2, key3, key4} = obj;
// key1 = "value1"
// key2 = "value2"
// key3 = "value3"
// key4 = undefined
// Can easily use `if` here on key4
if(!key4) { console.log("key not present"); } // Key not present
Do check other use of JavaScript Destructuring

ES6 syntax reference: use spread and boolean short circuiting to conditionally add fields to an object during declaration

I want to construct an object like this:
const obj = {
a: 'a', // only add this if "someCondition" is true
b: 'b', // only add this if "someCondition" is false
always: 'present', // add this in any case
}
This works:
const obj = { always: 'present' }
if (someCondition) { obj.a = 'a' }
if (!someCondition) { obj.b = 'b' }
However, I'm looking for a more concise way using ES6 syntax.
It is possible using ES6 syntax to conditionally add fields during declaration of an object.
This is useful if the consumer of the object will not tolerate fields with null / undefined / whatever values, and you do not want to have to write multiple statements to correctly declare the object:
const obj = {
...(someCondition && {a: 'a'}),
...(!someCondition && {b: 'b'}),
always: 'present'
}
So how does that work ? Lets look at ...(true && {a: 'a'}). The ES6 spread operator "..." will iterate each of the field->value pairs in { "a": "a" } applying them to x.
The true && x expression will return x, whereas false && x will return false. This is known as short circuit evaluation
So if the logical expression is true then the spread operator will add the fields, and if it is not true it will not add anything.

Checking 'undefined' or 'null' of any Object

I am working on Angular project and time to time I used to have check undefined or null over Object or it's properties. Normally I use lodash _.isUndefined() see example below:
this.selectedItem.filter(i => {
if(_.isUndefined(i.id)) {
this.selectedItem.pop();
}
})
I couldn't see any problem with it. But I had discussion with my colleague during review of above code. He was telling me that if i gets undefined before the if statement then it will throw the exception. Instead he suggested me to always check i or i.id like this:
if(!!i && !!i.id) {
this.selectedItem.pop();
}
I am convinced what he was trying to say unlike his way of checking undefined in above code. But then I was thinking what is the purpose of lodash _.isUndefined?
Could anyone please let me know what is the best or clean way to do it. Because for me !!i && !!i.id is not readable at all.
Many thanks in advance.
You can use _.isNil() to detect undefined or null. Since you're using Array.filter(), you want to return the results of !_.isNil(). Since i is supposed to be an object, you can use !_.isNil(i && i.id).
Note: you are using Array.filter() as Array.forEach(). The callback of Array.filter() should return a boolean, and the result of the filter is a new array.
const selectedItem = [
undefined,
{},
{ id: 5 },
undefined,
{ id: 7 },
];
const result = selectedItem.filter(i => !_.isNil(i?.id));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
You can also use _.reject() and save the need to add !:
const selectedItem = [
undefined,
{},
{ id: 5 },
undefined,
{ id: 7 },
];
const result = _.reject(selectedItem, i => _.isNil(i?.id));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Use typeof i.id === 'undefined' to check for undefined and i.id === null to check for null.
You could write your own helper functions to wrap any logic like what LoDash has. The condition with !!i && !!i.id is only looking for falsy values (empty string, 0, etc), not only null or undefined.
You could check for i and if it is not truthy or if the property is undefined or null, then do something.
if (!i || i.id === undefined || i.id === null) {
this.selectedItem.pop();
}
Referring to a variable which has undefined as it's value won't throw any error. You get a ReferenceError for referring to variable that is not defined:
> i
Uncaught ReferenceError: i is not defined
If you pass a not-defined variable to a function a ReferenceError is thrown and the function won't be executed.
> _.isUndefined(i)
Uncaught ReferenceError: i is not defined
typeof operator should be used for safely checking whether a variable is defined or not:
> typeof i
'undefined'
In your code the i is defined (it's a function argument) so by referring to it you won't get any ReferenceError. The code will throw a TypeError when i is defined, has undefined value and you are treating it as an object:
> var i = undefined; i.id
Uncaught TypeError: Cannot read property 'id' of undefined
let words = [null, undefined, 'cheaters', 'pan', 'ear', 'era']
console.log(words.filter(word => word != null));
Your friend is right. When you do, _.isUndefined(i.id) you're assuming i to not to be undefined. You're assuming i is an object which will have an id property which you're checking if it is falsey or not.
What happens when the variable i itself is undefined? So you will end up undefined.id which is an error. Therefore you could simply do this
if(i && i.id) {
// You're good to go
}
The above will check for all falsey values, 0 and "" included. So if you want to be very specific, then you'll have to check the types of both using typeof operator.
May I suggest checking for if(typeof(element) == "number" && element) {} In this case the typeof() part catches any non numbers and the element part should catch any NaNs (typeof(NaN) returns "number")
You can use lodash#get (it will handle if the root is value null or undefined), and then compare the output with null using == or !=, instead of using === or !==. if the output is null or undefined then comparing with == will be true and != will be false.
const selectedItem = [
undefined,
{},
{id: null},
{ id: 5 },
undefined,
{ id: 0 },
{ id: 7 },
];
const res = selectedItem.filter(a => _.get(a, 'id') != null);
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
using lodash#get you can checkfor any nested level for its existence with out subsequent && like a && a.b && a.b.c && a.b.c.d (in case of d) look at this answer of mine for nested level checking with lodash#get
Also you can use _.isNill instead of comparing with null will == or !=
Another more "lodashy" approach would be to use _.conforms. The readability is much better in my opinion and you get access directly to id so no problems with undefined before that:
const items = [
undefined,
{ id: null},
{ id: 5 },
{ id: "4" },
{ id: undefined },
undefined,
{ id: 0 },
{ id: 7 },
{ id: () => 3 }
];
const numbersOnly = _.filter(items, _.conforms({'id': _.isNumber}));
console.log('numbers', numbersOnly);
const allDefined = _.filter(items, _.conforms({'id': _.negate(_.isUndefined)}));
console.log('defined', allDefined);
const stringsOnly = _.filter(items, _.conforms({'id': _.isString}));
console.log('strings', stringsOnly);
const functionsOnly = _.filter(items, _.conforms({'id': _.isFunction}));
console.log('functions', functionsOnly);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Javascript has now (Chrome 80, Safari 13.4) Optional chaining (?.)
The optional chaining operator (?.) permits reading the value of a
property located deep within a chain of connected objects without
having to expressly validate that each reference in the chain is
valid.
This means you could check for id without causing an exception in case i is undefined
this.selectedItem.filter(i => {
if(i?.id) {
this.selectedItem.pop();
}
})
Or since you are using filter, you can check test this live on the filter documentation.
const words = ['spray', undefined, 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word?.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
Additionally, also worth to mention, as #Koushik Chatterjee's answer points, lodash _.get allows you to describe a path to a deep property safely, and even give a default value in case it doesn't exist.
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, ['a', '0', 'b', 'c']);
// => 3
_.get(object, 'a.b.c', 'default');
// => 'default'

use JSON.parse reviver to force value of undefined in resulting object rather than cause property to be omitted

JSON.parse takes serialized JSON as an argument and deserializes it. The second (optional) argument is a reviver function, taking a key and value and returning the replacement value in the deserialized object. It is documented behavior that the reviver, if it returns undefined or nothing, the property in question will be omitted from the resulting deserialized object.
I have a situation where I would like the property in question to be INCLUDED in the resulting deserialized object with the value of undefined.
So, for example, the following is currently true:
JSON.parse(JSON.stringify({a: 1, b:2}), (k, v) => v===2 ? undefined : v);
// result of this is {a:1}, as is documented/expected.
But what if I actually want the result to be
{a:1, b:undefined}
Is there any way to write the reviver to do this?
I specifically don't want to iterate through the object again after the deserialization, so please don't suggest that as a solution. Also I specifically don't want b to be set as null. I really want it to be present as a property with the value undefined.
It may simply not be possible, but I'm hoping someone has a nifty idea!
FIRST EDIT:
First suggestion was great try, but I also need it to work in deep structures, so the following:
JSON.parse(JSON.stringify({
a: 1,
b:{
c: 1,
d: 2,
e: [
1,
2,
{
f: 1,
g: 2
},
4
]
}
}), (k, v) => v===2 ? undefined : v);
should in my ideal world yield:
{
a: 1,
b:{
c: 1,
d: undefined,
e: [
1,
undefined,
{
f: 1,
g: undefined
},
4
]
}
}
I doubt this can be done with a simple reviver and JSON.parse.
I don't know if this will satisfy your constraints, and it's ugly as sin, but here's an approach: wrap JSON.parse in something that stores the undefined keys from your reviver and adds them back at the end. This does not entail iterating your object again, which you explicitly rejected, but it does iterate the list of undefined keys:
const myParse = (obj, reviver) => {
if (typeof reviver !== 'function') {
return JSON.parse(obj)
}
const undefs = []
const rev = (k, v) => {
const val = reviver(k, v)
if (typeof val === 'undefined') {
undefs.push(k)
}
return val;
}
const ret = JSON.parse(obj, rev)
undefs.forEach(k => ret[k] = undefined)
return ret
}
const result = myParse(
JSON.stringify({a: 1, b:2}),
(k, v) => v===2 ? undefined : v
)
console.log(result)

Categories