0

I'm just creating a function that will JSON.stringify an input but also detecting NaN on number inputs, but don't want to use typeof because of reasons stated below. The input could be either a number, boolean or string. Nothing more.

I've reached the situation where NaN !== NaN, so:

if (input !== input || input === Infinity || input === -Infinity) {
    output = input.toString();
} else {
    output = JSON.stringify(input);
}

I'm doing it this way because JSON.stringify() returns "null" when the value is NaN or Infinity.

I know that with typeof and toString() this is pretty easy to achieve, but some performance tests shows that typeof under IE11 is really slow (4-5 times slower than JSON.stringify() under our situation), and we need to focus on IE11 here.

I would like to know if there are more cases where val !== val.

Here you have a performance test: https://jsperf.com/typeof-vs-nan-nan2 Not used the SO one because seems that they run the codes server side, as there IE performance is as good as elsewhere. Impossibru thing.

Local test is:

var mockdata = [];

function notToJson(val) {
    return val !== val || val === Infinity || val === -Infinity;
}

for (var i = 0; i < 500000; i++) {
    var n = Math.floor(Math.random()*1000000);
    if (Math.random()>0.5) {
        n = n.toString();
    } else if (Math.random()>0.5) {
        if (Math.random()>0.5) {
            n = NaN;
        } else {
            if (Math.random()>0.5) {
                n = Infinity;
            } else {
                n = -Infinity;
            }
        }
    }
    mockdata.push(n);
}

console.time("typeof");
for (i = 0; i < 500000; i++) {
    var res = typeof mockdata[i] === "string";
}
console.timeEnd("typeof");

console.time("notToJson");
for (i = 0; i < 500000; i++) {
    res = notToJson(mockdata[i]);
}
console.timeEnd("notToJson");

console.time("toString");
for (i = 0; i < 500000; i++) {
    res = mockdata[i].toString();
}
console.timeEnd("toString");

console.time("JSON.stringify");
for (i = 0; i < 500000; i++) {
    res = JSON.stringify(mockdata[i]);
}
console.timeEnd("JSON.stringify");

console.time("Full typeof");
for (i = 0; i < 500000; i++) {
    res = typeof mockdata[i]==="string"?JSON.stringify(mockdata[i]):mockdata[i].toString();
}
console.timeEnd("Full typeof");

console.time("Full notToJson");
for (i = 0; i < 500000; i++) {
    res = notToJson(mockdata[i])?mockdata[i].toString():JSON.stringify(mockdata[i]);
}
console.timeEnd("Full notToJson");

Chrome output is:

enter image description here

But IE11 output is:

enter image description here

I've noticed that the less strings mockdata has, the performance of typeof is noticeably increased (Talking about IE11).

Jorge Fuentes González
  • 11,568
  • 4
  • 44
  • 64

2 Answers2

2

Here are some cases where val !== val returns true:

console.log({} !== {}); // true
console.log(new Date() !== new Date()); // true
console.log(new String("") !== new String("")); // true

That only applies when the objects are different:

var a = b = {}; // now they are equal
console.log(a !== b); // false

It also happens with Symbols (ES6 feature):

console.log(Symbol() !== Symbol()); // true
Aloso
  • 5,123
  • 4
  • 24
  • 41
  • All these are different objects, as already stated in the comments. Note the `val` in `val !== val`. I want to assign something to a variable and check that variable. – Jorge Fuentes González Oct 03 '18 at 10:00
1

I'm going to answer this myself as I don't like to have unanswered questions.

Note how the question talks about val. What I mean is to assign a value to a variable, and later compare the variable with itself. Not to create two different variables and compare them.

From my own tests, val !== val only when val = NaN, so:

var val = NaN;
console.log("val !== val:", val !== val);

The reason is right here: Why is NaN not equal to NaN?

Jorge Fuentes González
  • 11,568
  • 4
  • 44
  • 64