目录:

  • 变量的那些事
  • JavaScript数据类型
  • isNaN 的检测机制是怎样的?
  • 得出解决问题的方案

前言

变量和数据类型是学习JavaScript最先接触到的东西,但是往往看起来最简单的东西往往还隐藏着很多你不了解、或者容易犯错的知识 ,比如下面几个问题:

  • 创建变量的方式有哪些?
  • JavaScript 中的数据类型有哪些?
  • 检测数据类型的方式有哪些?
  • NaN 属于数字类型吗?
  • isNaN 的检测机制是怎样的?

如果你还不能很好的解答上面的问题,那说明你还没有完全掌握这部分的知识,那么请好好阅读下面的文章吧。

本文将从一个问题入手,通过介绍JavaScript中的变量和类型相关知识以及 isNaN 的检测机制。希望你看完这篇文章,可以知道这个问题的答案。废话少说,进入正题。

一、变量那些事儿

1.1 变量是啥?

变量: 它不是指具体的值,只是一个用来存储具体值的「容器」 或者「代名词」 ,因为它存储的值可以改变,所以称为变量。

那如何理解变量呢?举个简单的例子:

var num = 10;
num = 15;
console.log(num + 5); 
// 在控制台打印出 20,这就体现到了 num 这个变量只是存储具体值而已,一开始 num 存储 10,之后赋值为 15,结果就是 20。简单来说,变量就是经常变的,重点在 「变」 这个字上。
复制代码

1.2 创建变量的方式

下面只是简单说明创建变量的方式,暂时不深入讲解,之后会往深里学,往深里讲。

  • var(ES3)创建的是变量
  • function(ES3) 创建函数「函数和变量没有什么区别,函数名也是变量,只不过存储的值是函数类型的而已」
  • let(ES6)创建的是变量
  • const(ES6)创建的是常量
  • import(ES6)基于 ES6 的模块规范导出需要的信息
  • class(ES6)基于 ES6 创建类

1.3 变量的命名规范

  • 严格区分大小写
  • 遵循驼峰命名法:按照数字、字母、下划线或者$来命名(数字不能作为名字的开头),命名的时候基于英文单词拼接成一个完整的名字(第一个代词字母小写,其余每一个有意义单词的首字母都大写)
  • 不能使用关键字和保留字:在 JS 中有特殊含义的叫做关键字,未来可能会成为关键字的叫做保留字

注:变量的命名尽量见名知意,语义化更强一些。

二、JavaScript数据类型

2.1 变量的数据类型

  • 基本数据类型/值类型
    • 数字 number
    • 字符串 string
    • 布尔 boolean
    • null
    • undefined
    • Symbol 「ES6」
  • 引用数据类型
    • 对象类型
      • 普通对象
      • 正则对象
      • 数组
      • 日期对象
    • 函数

2.2 typeof 检测数据类型

在JS中用来检测数据类型的方式「此处简单介绍,不深入」:

  • typeof
  • instanceof
  • constructor
  • Object.prototype.toString.call()

本部分重点关注 typeof 检测数据类型的细节点,暂时不去关注其他检测数据的方法,将从语法、返回值、发现点来讲解 typeof 的使用与细节点。

语法:typeof [value] => 检测value的数据类型

返回值:使用typeof检测出来的结果是一个字符串,字符串中包含着对应的数据类型,例如:"number"/"string"/"boolean"/"undefined"/"object"/"function"

发现点:

  • typeof null 的结果是 "object" 因为 null 代表空对象指针(没有指向任何的内存空间)
  • 使用 typeof 检测数组/正则/对象,最后返回的是"object"。也就是说基于这种方式无法细分对象
  • typeof function 的结果是 "function"

三、isNaN 的检测机制是怎样的?

3.1 isNaN 的作用

说到 isNaN 的作用,就不得不先说一下 NaN,首先从字面上理解为 not a number,但是「它是数字类型的」,NaN 和谁都不相等,包括自己。那么问题来了,如何检测某个变量是不是有效数字呢?终于进入正题了,那就是 isNaN的作用。

isNaN:检测当前值是不是有效数字,返回true,代表非有效数字,返回false,代表有效数字

3.2 isNaN 的检测机制

  1. 首先验证当前要检测的值是否为数字类型的,如果不是,浏览器会默认的把值转换为数字类型「调用 Number 这个方法」
  2. 当前检测的值已经是数字类型,是有效数字,返回false,不是,返回true「数字类型中只有NaN不是有效数字,其余都是有效数字」

重点是:调用 Number 这个方法,把非数字类型的值转换为数字,下面举例子,以便读者更好的理解 Number 这个方法。

其它基本类型转换为数字:直接使用Number这个方法转换的

【字符串转数字】

Number('13') // => 13
Number('13px') // => NaN 如果当前字符串中出现任意一个非有效数字字符,结果则为NaN
Number('13.5') // => 13.5 可以识别小数
Number('13.5.0') // => NaN
复制代码

【布尔转数字】

Number(true) // => 1
Number(false) // => 0
复制代码

【其它转数字】

Number(null) // => 0
Number(undefined) // => NaN
复制代码

引用数据类型转换为数字:先把引用值调取 toString 转换为字符串,然后再把字符串调取 Number 转换为数字

【对象转数字】

({}).toString() // => '[object Object]' => NaN
复制代码

【数组转数字】

[12,23].toString() // => '12,23' => NaN
[12].toString() // => '12' => 12
[].toString() // => '' => 0
复制代码

【正则转数字】

/^$/.toString() // => "/^$/" => NaN
复制代码

3.3 检验是否理解 isNaN 的检测机制

如果你能快速地看出下面代码执行结果,并且完全正确,就说明你已经完全理解 isNaN 的检测机制。

var num = 12;
isNaN(num); // 检测num变量存储的值是否为有效数字 false

isNaN('13'); // => false
isNaN('乐少');  // => true
isNaN(true); // => false
isNaN(false); // => false
isNaN(null); // => false
isNaN(undefined); // => true
isNaN({age:9});	// => true
isNaN([12,13]); // => true
isNaN([12]); // => false
isNaN(/^$/); // => true
isNaN(function(){}); // => true
复制代码

四、回到最初的起点

下面是 num 这个变量是已经声明的,但是 num 变量存储的值不能确定。

方案一:

if(Number(num) == NaN){
    alert('num不是有效数字!')
}
复制代码

方案二:

if(isNaN(num)){
   alert('num不是有效数字!')
}
复制代码

方案三:

if(typeof num === 'number' && isNaN(num)){
   // => 检测是否为有效数字,只有这一种方案 
   alert('num不是有效数字!')
}
复制代码

看完整篇文章+我列出来的三个方案,我相信你心中已经有了明确的答案,我下面逐个方案进行分析:

方案一:假设 Number(num) 的结果是 NaN,但是代码执行的结果是不会出现弹窗,因为 NaN和谁都不相等,条件永远不成立(即使 num 确实不是有效数字,转换的结果确实是 NaN ,但是NaN!= NaN的)

方案二:这个方案看起来已经是正确答案,但是忽略了 其他数据类型的值可以转为数字类型,例如,假设 num 的值为 '13',首先会调用 Number 将 '13' 变成 13,然后再使用 isNaN(13) 得出结果为 false,但是 '13' 并不是一个有效的数字。

方案三:我个人认为这个方案是能够解决文章标题提出的问题,首先先判断 变量是否为 数字类型,然后再使用 isNaN 判断变量是不是有效数字?&& 运算符,需要两边同时成立的时候,结果才为 true,所以当 typeof num === 'number' 这个结果为 false 的话,就说整个判断条件的结果都为 false。