@bytesnz

Jack Farley, Web Application Engineer

NaN Got Me

NaN Got Me

Today I modified the script I had made for cleaning and correlating the
Reef Doctor fisheries data to calculate catch weight per fishing gear. A quick
job, I modified the final catch processing script to add up the weights per
gear and set it running.

Looking at the log file and the generated JSON, I noticed that the weights
were only showing up as null. A quick glance at the code, it all looked fine,
so I tried running it again to make sure I wasn’t going crazy. Sure enough, I
wasn’t. Enter rubber duck.

So for every trip, if the trip has catch data, I go through catch items,
determining the gear used for the catch item, then adding the weights to the
catch gear weight.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Object.keys(data).forEach((id) => {
let item = data[id];
// Calculate total catch weight
if (item.catch) {
// Store catch stats per gear
item.gearWeights = {};
/* If the number of fish in one species is too large to count individual
* fish, the total species weight will be recorded and 10 individuals will
* be measured so that an average can be obtain for the total species
* catch. If the item is part of a large catch, the individual weights
* should not be included in the catch weights.
*/
for (i = 0; i < item.catch.length; i++) {
let catchItem = item.catch[i];
const itemGear = catchItem.gear || (item.gear && item.gear.length === 1 && item.gear[0].type) || 'unknown';
if (item.gearWeights[itemGear] === 'undefined') {
item.gearWeights[itemGear] = 0;
}
...
if (catchItem.totalWeight) {
lastTotalSpecies = catchItem.species;
totalWeight += catchItem.totalWeight;
item.gearWeights[itemGear] += catchItem.totalWeight;
...
} else if (catchItem.weight && !lastTotalSpecies) {
totalWeight += catchItem.weight;
item.gearWeights[itemGear] += catchItem.weight;
}
}

A quick glances at the additions didn’t come up with anything - how were they
coming up with and answer of null? The answer was the initiation (or lack
thereof the gear weight:

1
2
3
...
if (item.gearWeights[itemGear] === 'undefined') {
...

This, of course what not what I was meaning, missing out the typeof operator,
so the gear weight was never being initialised. Adding a number to undefined
results in NaN, which can then be added to as much as you like without a
change in value.

stringifying the resultant gear weight resulted in the tricksy (censored)
null value in JSON.

1
2
3
4
undefined + 1 // = NaN
NaN + 1 // = NaN
NaN + 1 + 1 // = NaN
JSON.stringify(NaN) // = null