1

So first off this is not an issue I am facing. I was going through some Javascript blogs when I encountered the Array prototype methods of .indexOf and .includes. So if an array has NaN as a value, then probably indexOf is not going to be able to figure it out and I am left with using .includes. But my question here is, since the browser compatibility of includes actually excludes IE, what should be the alternative to detect the NaN check? I thought of constructing a polyfill by referring this

if (Array.prototype.includes) {
  Object.defineProperty(Array.prototype, "includes", {
    enumerable: false,
    value: function(obj) {
        var newArr = this.filter(function(el) {
          return el == obj;
        });
        return newArr.length > 0;
      }
  });
}

var arr = [NaN];
console.log(arr.includes(NaN));

But unfortunately, it is returning false as well. So what other options do I have? Or am I missing something out?

Community
  • 1
  • 1
Krishna Prashatt
  • 631
  • 9
  • 18
  • You can find index of NaN using `arr.findIndex()` – Syed mohamed aladeen May 10 '19 at 10:25
  • 3
    A polyfill for `includes()` can be [found on MDN](https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Array/includes). – Tigger May 10 '19 at 10:26
  • @VLAZ That's what I thought too initially, but that's actually not the case! See https://www.ecma-international.org/ecma-262/7.0/#sec-samevaluezero , `NaN` is the one exception. `If x is NaN and y is NaN, return true.` – CertainPerformance May 10 '19 at 10:28
  • @CertainPerformance yep, appears I'm wrong here. For some reason I thought I have even used `[NaN].includes(NaN)` in the past and gotten `false`. Anyway, the MDN implementation should be the correct one – VLAZ May 10 '19 at 10:29
  • Note that your polyfill should probably change `if (Array.prototype.includes) {` to `if (!Array.prototype.includes) {` – CertainPerformance May 10 '19 at 10:31
  • @CertainPerformance yes that I am clear, I just removed the negation so that the `includes` method actually executes this part of the code and not the default one. – Krishna Prashatt May 10 '19 at 10:32

3 Answers3

1

You can include a polyfill for Number.isNaN as well, and then use it in your filter test - if both the obj and el pass Number.isNaN, then return true:

Number.isNaN = Number.isNaN || function(value) {     
    return value !== value;
}

// if (!Array.prototype.includes) {
  Object.defineProperty(Array.prototype, "includes", {
    enumerable: false,
    value: function(obj) {
        var newArr = this.filter(function(el) {
          return el == obj || Number.isNaN(el) && Number.isNaN(obj);
        });
        return newArr.length > 0;
      }
  });
// }

var arr = [NaN];
console.log(arr.includes(NaN));
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
1

Array#includes uses the Same-Value-Zero algorithm, which is not the same as ==.

Same-Value is provided by Object.is(), and you can manually check for -0 and +0 to get the "-Zero" part of the check.

The linked page includes a polyfill, although since the polyfill includes a step to make -0 and +0 different - which you don't want in a Same-Value-Zero algorithm - you can just leave it out and simplify accordingly:

function SameValueZero(x, y) {
    return x === y || (x !== x && y !== y);
}
Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
0

You can find the index of NaN using firstIndex. try like this.

var arr = [NaN];
let index = arr.findIndex(Number.isNaN)
console.log(index >= 0);
Syed mohamed aladeen
  • 6,507
  • 4
  • 32
  • 59
  • If `includes` has to be polyfilled, then I doubt either `findIndex` or `Number.isNaN` would be available. – VLAZ May 10 '19 at 10:32
  • Also, `(index >= 0)?true:false` is completely redundant. `index >= 0` returns a boolean, so if the boolean returned is `true`, the ternary then returns...`true`. And if the boolean is `false`, it returns `false`. – VLAZ May 10 '19 at 10:33
  • @VLAZ ohh sry I missed it!! – Syed mohamed aladeen May 10 '19 at 10:35
  • Though this provides the answer, as @VLAZ mentioned, both `findIndex` and `Number.isNaN` is not supported in IE :( – Krishna Prashatt May 10 '19 at 10:36