With this babel plugin, use .hasNil
to traverse chained object properties and determine whether any of them return null
or undefined
.
This plugin is inspired by babel-plugin-transform-isNil, however the use case and internals are different.
const house = { kitchen: { drawer: [ ] } }
const drawer = 'drawer'
const goTo = function(location) {
return location
}
if(house.kitchen.hasNil) { /* false */
console.log('this will not run')
}
// with a string literal
if(house['kitchen'].hasNil) { /* false */
console.log('this will not run')
}
// with a variable
if(house.kitchen[drawer].hasNil) { /* false */
console.log('this will not run')
}
// with a function using bracket notation
if(house[goTo('kitchen')].drawer.hasNil) { /* false */
console.log('this will not run')
}
// with a number literal
if(house.kitchen.drawer[3].hasNil) { /* true */
console.log('this will run')
}
// you can chain as many properties as you want
if(house[goTo(kitchen)].drawer[3]['sub-drawer'].forks.hasNil) { /* true */
console.log('this will run')
}
if(house.basement.closet[3].hasNil) { /* true */
console.log('this will run')
}
// Unsupported:
// chaining functions using dot notation
if(house.foo().hasNil) { /* will not work */
console.log('this will not work')
}
// logical operators
if((house || { }).hasNil) { /* will not work */
console.log('this will not work')
}
Due to Babel not handling the Proxy object, this plugin is only compatible with Node versions >= 6.0.0.
First, add the babel-plugin-transform-hasnil
package via your preferred package manager:
npm install --save-dev babel-plugin-transform-hasnil
Then register with babel, such as by using the .babelrc
file.
{
"plugins": [ "babel-plugin-transform-hasnil" ]
}
Summary: using hasNil
is not as fast as using pure logical operators or isNil
(which compiles to the same thing). In general, however, this should only impact you if you're looping > 10,000 times.
Here's a benchmark:
const entry = { first: { second: [ { third: { fourth: { } } } ] } }
The goal is to determine whether first.second[0].third.fourth
returns null
or undefined
.
Operator logic:
(entry === null) || (entry === undefined) || (entry.first === null) || (entry.first === undefined) || (entry.first.second === null) || (entry.first.second === undefined) || (entry.first.second[0] === null) || (entry.first.second[0] === undefined) || (entry.first.second[0].third === null) || (entry.first.second[0].third === undefined) || (entry.first.second[0].third.fourth === null) || (entry.first.second[0].third.fourth === undefined)
isNil logic (does not support number literals such as [0]
):
entry.isNil || entry.first.isNil || entry.first.second.isNil || (entry.first.second[0] === null) || (entry.first.second[0] === undefined) || (entry.first.second[0].third === null) || (entry.first.second[0].third === undefined) || (entry.first.second[0].third.fourth === null) || (entry.first.second[0].third.fourth === undefined)
hasNil logic:
entry.first.second[0].third.fourth.hasNil
Results:
cycles | operator | isNil | hasNil |
---|---|---|---|
100 | 0 ms | 0 ms | 0 ms |
1,000 | 0 | 0 | 2 |
10,000 | 1 | 1 | 24 |
Contributions are always welcome. You are encouraged to open issues and merge requests.
To run the tests, use npm run test
.