ESLint意外使用isNaN

Eli*_*cia 120 javascript eslint

我正在尝试isNaN在Node.js模块中使用箭头函数内的全局函数,但我收到此错误:

[eslint] Unexpected use of 'isNaN'. (no-restricted-globals)

这是我的代码:

const isNumber = value => !isNaN(parseFloat(value));

module.exports = {
  isNumber,
};
Run Code Online (Sandbox Code Playgroud)

我知道自己做错了什么吗?

PS:我正在使用AirBnB风格指南.

And*_*ell 218

正如文档所示,使用Number.isNaN.

const isNumber = value => !Number.isNaN(parseFloat(value));
Run Code Online (Sandbox Code Playgroud)

引用Airbnb的文件:

为什么?全局isNaN强制非数字到数字,对于强制NaN的任何东西都返回true.如果需要此行为,请将其显式化.

// bad
isNaN('1.2'); // false
isNaN('1.2.3'); // true

// good
Number.isNaN('1.2.3'); // false
Number.isNaN(Number('1.2.3')); // true
Run Code Online (Sandbox Code Playgroud)

  • 但是`isNaN`和`Number.isNaN`不是相同的功能.例如```isNaN('1a')true Number.isNaN('1a')false``` (20认同)
  • 请注意,Number.isNaN在IE11中不起作用 (8认同)
  • 多么愚蠢的规则,重点是强制转换为一个数字,或者你也可以做一个 `typeof` 检查。 (4认同)
  • @rosencreuz更像不良行为。这就是在上面的示例中有`Number('1.2.3')`的原因。 (2认同)

thy*_*ian 13

仅供参考,这对IE不起作用.在此处查看浏览器兼容性.


Vin*_*net 10

将未知类型强制转换为数字会导致 javascript 中出现意外结果,eslint 规则会阻止您强制使用 isNaN,isNaN 应该仅用于检查数字是否等于特定的 NaN 值。这是 javascript。以下函数检查可防止您将非数字值强制转换为数字。

/**
 * Return true if the value can be evaluated as a Number.
 * @param {*} value
 * @param {boolean} finite - If true, treat non-finite numbers as invalid.
 */
const isNumeric = (value, finite = false) =>
  (typeof value === 'number' ||
    (typeof value === 'string' && value.trim() !== '')) &&
  (finite ? Number.isFinite(Number(value)) : !Number.isNaN(Number(value)));
Run Code Online (Sandbox Code Playgroud)

测试用例,您可以切换 isNumeric 来isNumeric(v) => typeof isNaN(v) === 'number'查看哪些情况无法直接强制强制任何值(使用 Number() 或 +string 具有相同的问题)

describe('isNumeric', () => {
  it('evaluate "1" as numeric', () => {
    expect(isNumeric('1')).to.equal(true);
    expect(isNumeric('1', true)).to.equal(true);
  });
  it('evaluate "1.1" as numeric', () => {
    expect(isNumeric('1.1')).to.equal(true);
    expect(isNumeric('1.1', true)).to.equal(true);
  });
  it('evaluate "100.145864" as numeric', () => {
    expect(isNumeric('100.145864')).to.equal(true);
    expect(isNumeric('100.145864', true)).to.equal(true);
  });
  it('evaluate 1 as numeric', () => {
    expect(isNumeric(1)).to.equal(true);
    expect(isNumeric(1, true)).to.equal(true);
  });
  it('evaluate 1.1 as numeric', () => {
    expect(isNumeric(1.1)).to.equal(true);
    expect(isNumeric(1.1, true)).to.equal(true);
  });
  it('evaluate 100.145864 as numeric', () => {
    expect(isNumeric(100.145864)).to.equal(true);
    expect(isNumeric(100.145864, true)).to.equal(true);
  });
  it('evaluate "one" as non-numeric', () => {
    expect(isNumeric('one')).to.equal(false);
    expect(isNumeric('one', true)).to.equal(false);
  });
  it('evaluate undefined as non-numeric', () => {
    expect(isNumeric(undefined)).to.equal(false);
    expect(isNumeric(undefined, true)).to.equal(false);
  });
  it('evaluate null as non-numeric', () => {
    expect(isNumeric(null)).to.equal(false);
    expect(isNumeric(null, true)).to.equal(false);
  });
  it('evaluate NaN as non-numeric', () => {
    expect(isNumeric(NaN)).to.equal(false);
    expect(isNumeric(NaN, true)).to.equal(false);
  });
  it('evaluate true as non-numeric', () => {
    expect(isNumeric(true)).to.equal(false);
    expect(isNumeric(true, true)).to.equal(false);
  });
  it('evaluate false as non-numeric', () => {
    expect(isNumeric(false)).to.equal(false);
    expect(isNumeric(false, true)).to.equal(false);
  });
  it('evaluate an empty string as non-numeric', () => {
    expect(isNumeric('')).to.equal(false);
    expect(isNumeric('', true)).to.equal(false);
  });
  it('evaluate "100,2" as non-numeric', () => {
    expect(isNumeric('100,2')).to.equal(false);
    expect(isNumeric('100,2', true)).to.equal(false);
  });
  it('evaluate "1.1.1" as non-numeric', () => {
    expect(isNumeric('1.1.1')).to.equal(false);
    expect(isNumeric('1.1.1', true)).to.equal(false);
  });
  it('evaluate "123123 + 123123" as non-numeric', () => {
    expect(isNumeric('123123 + 123123')).to.equal(false);
    expect(isNumeric('123123 + 123123', true)).to.equal(false);
  });
  it('evaluate "123123 - 123123" as non-numeric', () => {
    expect(isNumeric('123123 - 123123')).to.equal(false);
    expect(isNumeric('123123 - 123123', true)).to.equal(false);
  });
  it('evaluate "123123 / 123123" as non-numeric', () => {
    expect(isNumeric('123123 / 123123')).to.equal(false);
    expect(isNumeric('123123 / 123123', true)).to.equal(false);
  });
  it('evaluate "123123 * 123123" as non-numeric', () => {
    expect(isNumeric('123123 * 123123')).to.equal(false);
    expect(isNumeric('123123 * 123123', true)).to.equal(false);
  });
  it('evaluate "  " as non-numeric', () => {
    expect(isNumeric('  ')).to.equal(false);
    expect(isNumeric('  ', true)).to.equal(false);
  });
  it('evaluate " " as non-numeric', () => {
    expect(isNumeric(' ')).to.equal(false);
    expect(isNumeric(' ', true)).to.equal(false);
  });
  it('evaluate Infinity as numeric', () => {
    expect(isNumeric(Infinity)).to.equal(true);
  });
  it('evaluate -Infinity as numeric', () => {
    expect(isNumeric(-Infinity)).to.equal(true);
  });
  it('evaluate Infinity as non-numeric with finite=true', () => {
    expect(isNumeric(Infinity, true)).to.equal(false);
  });
  it('evaluate -Infinity as non-numeric with finite=true', () => {
    expect(isNumeric(-Infinity, true)).to.equal(false);
  });
  it('evaluate Number.MAX_SAFE_INTEGER as numeric', () => {
    expect(isNumeric(Number.MAX_SAFE_INTEGER)).to.equal(true);
    expect(isNumeric(Number.MAX_SAFE_INTEGER, true)).to.equal(true);
  });
  it('evaluate Number.MIN_SAFE_INTEGER as numeric ', () => {
    expect(isNumeric(Number.MIN_SAFE_INTEGER)).to.equal(true);
    expect(isNumeric(Number.MIN_SAFE_INTEGER, true)).to.equal(true);
  });
  it('evaluate "1e3" as numeric ', () => {
    expect(isNumeric('1e3')).to.equal(true);
    expect(isNumeric('1e3', true)).to.equal(true);
  });
  it('evaluate "1e.3" as non-numeric ', () => {
    expect(isNumeric('1e.3')).to.equal(false);
    expect(isNumeric('1e.3', true)).to.equal(false);
  });
  it('evaluate "1e3.3" as non-numeric ', () => {
    expect(isNumeric('1e1.3')).to.equal(false);
    expect(isNumeric('1e1.3', true)).to.equal(false);
  });
  it('evaluate "1e" as non-numeric ', () => {
    expect(isNumeric('1e')).to.equal(false);
    expect(isNumeric('1e', true)).to.equal(false);
  });
  it('evaluate "1e0" as numeric ', () => {
    expect(isNumeric('1e0')).to.equal(true);
    expect(isNumeric('1e0', true)).to.equal(true);
  });
  it('evaluate "-1e3" as numeric ', () => {
    expect(isNumeric('-1e3')).to.equal(true);
    expect(isNumeric('-1e3', true)).to.equal(true);
  });
  it('evaluate an object as non-numeric ', () => {
    expect(isNumeric({})).to.equal(false);
    expect(isNumeric({}, true)).to.equal(false);
  });
});
Run Code Online (Sandbox Code Playgroud)

如果您有合法的用例,您还可以在 eslint 配置文件的 overrides 部分中禁用该规则(或者直接使用Number(value)+value强制而不触发规则)。

琐事(替代版本使用 @Noby Fujioka 答案建议的 REGEXP,已更新以通过建议的测试用例

const isNumeric = (value, finite = false) => (typeof value === 'number' || (typeof value === 'string' && /^(([\-]?[0-9]+)([\.e][0-9]+)?)$/.test(value))) && (finite ? Number.isFinite(Number(value)) : !Number.isNaN(value));

isNaN 行为来自https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN

isNaN("NaN"); // true
isNaN(undefined); // true
isNaN({}); // true
isNaN("blabla"); // true
isNaN(true); // false, this is coerced to 1
isNaN(null); // false, this is coerced to 0
isNaN("37"); // false, this is coerced to 37
isNaN("37.37"); // false, this is coerced to 37.37
isNaN(""); // false, this is coerced to 0
isNaN(" "); // false, this is coerced to 0
Run Code Online (Sandbox Code Playgroud)