1、JavaScript中的数据类型
在JavaScript中,我们把数据可以分为基本类型和引用类型。
1)基本数据类型:Number、String、Boolean、Undefined、null、symbol(es6新增,表示独一无二的值),BigInt(es10新增)。
2)引用数据类型:Object。Object包括函数对象-Function、普通对象-Object、数组对象-Array、正则对象-RegExp、日期对象-Date、Math数学函数对象等。
注意:a、在数值类型中,存在一种特殊数值NaN,意思为“不是数值”(可以使其他任何类型,所以NaN!=NaN。),用于表示返回数值的操作失败了(不是抛出错误)。isNaN用来检测这个值是否为有效数字,不是有效数字则返回true,是有效数字返回false。
b、Undefined类型只有一个值就是特殊值undefined。当声明了变量但没有初始化时,就相当于给变量赋予了undefined值。
c、字符串一旦创建,值就不能改变了。如 let lang = "java"; lang = lang+"script" 。lang是先销毁再创建。
d、Null类型同样只有一个值,即特殊值null,表示一个空对象指针。这也是给typeof传一个 null 会返回 "object" 的原因。(let car = null; console.log(typeof car); // "object")只要变量要保存对象,如果暂时没有哪个对象可保存,就可以用null来填充。undefined值由null值派生而来。(console.log(null == undefined); // true)
e、基本数据类型和引用数据类型存储在内存中的位置不同。基本数据类型存储在栈中,存放的是对应的值;引用数据类型存储在堆中,在栈中存放的是指向堆内存的地址。
2、数据类型检测
1)typeof 检测数据类型的逻辑运算符
typeof 操作符返回一个字符串,表示未经计算的操作数的类型。直接在计算机底层基于数据类型的值(二进制)进行检测。
typeof 对于原始类型:除了 null 都可以显示正确的类型。
typeof对于对象:除了函数都会显示object。所以说typeof并不能准确判断变量到底是什么类型,所以想判断一个对象的正确类型,这时候可以考虑使用instanceof。
2)instanceof 检测是否为某个类的实例
instanceof 运算符用于检测构造函数(类型的)的 prototype 属性是否出现在某个实例对象的原型链上。
instanceof的实现原理:顺着原型链去找,直到找到相同的原型对象,返回true,否则为false。
3)constructor 检测构造函数
如果我创建一个对象,更改它的原型,constructor就会变得不可靠了
4)Object.prototype.toString.call 检测数据类型
如果需要通用检测数据类型,可以采用Object.prototype.toString,调用该方法,统一返回格式“[object Xxx]”的字符串,其中Xxx就是对象的类型。
对于Object对象,直接调用toString()就能返回[object Object];而对于其他对象,只要把Object.prototype.toString执行,让它里面的this变为要检测的值,即需要通过call来调用,才能返回正确的类型信息。
总结:
typeof会返回一个变量的基本类型;instanceof返回的是一个布尔值;constructor返回的是一个布尔值;
instanceof可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型;我们可以肆意的修改原型的指向,所以检测不准确。
而typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外,因为对象存储在计算机中,都是以000开始的二进制存储,null也是,所以检测出来的结果是对象),但是引用数据类型中,除了function 类型以外,其他的也无法判断(“object”)。
实现:
传递的值是null或者undefined,就返回对应的字符串。基本数据类型都采用typeof检测。其他使用Object.prototype.toString。
3、JavaScript中的类型转换机制
我们在声明的时候只有一种数据类型,只有到运行期间才会确定当前类型。虽然变量的数据类型是不确定的,但是各种运算符对数据类型是有要求的,如果运算子的类型与预期不符合,就会触发类型转换机制。常见的类型转换有:强制转换(显示转换)、自动转换(隐式转换)
1)常见的显示转换方法有:Number()、parseInt()、String()、Boolean()
Number() 函数是将任意类型的值转化为数值。转化规则如下:
parseInt() 函数逐个解析字符,遇到不能转换的字符就停下来。
parseInt() 方法首先查看位置 0 处的字符,判断它是否是个有效数字;如果不是,该方法将返回 NaN,不再继续执行其他操作。但如果该字符是有效数字,该方法将查看位置 1 处的字符,进行同样的测试。这一过程将持续到发现非有效数字的字符为止,此时 parseInt() 将把该字符之前的字符串转换成数字。例如,如果要把字符串 "12345red" 转换成整数,那么 parseInt() 将返回 12345,因为当它检查到字符 r 时,就会停止检测过程。
字符串中包含的数字字面量会被正确转换为数字,比如 "0xA" 会被正确转换为数字 10。不过,字符串 "22.5" 将被转换成 22,因为对于整数来说,小数点是无效字符。
parseInt() 方法还有基模式,可以把二进制、八进制、十六进制或其他任何进制的字符串转换成整数。基是由 parseInt() 方法的第二个参数指定的,所以要解析十六进制的值,需如下调用 parseInt() 方法:var iNum1 = parseInt("AF", 16);//返回 175。
parseInt(string,radix)
在没有指定radix或者radix为0的情况下,parseInt会按十进制进行转换。然而,这在某些情况下有点特殊:
如果string的值以“0x”开头,parseInt会按十六进制进行转换;
如果string的值以“0”开头,parseInt会按八进制进行转换。
parseInt("0x10"); //字符串以0x开头则将之后的数字按16进制解读,16进制的10也就是十进制的16, 因此输出为16
parseInt("0xa"); //10,要注意16进制包括0~9,a~f (也就是10~15),超出该范围的字符不被解读。
parseInt("0xg"); //NAN
这三个例子分别等价于 parseInt("0x10",16) parseInt("0xa",16) parseInt("0xg",16)/
parseInt()的参数是一个字符串类型;parseInt 会先调用 toString 方法。对于小于 1e-6 的数值来说,ToString 时会自动转换为科学计数法。 数值0.0000000007先会被转换成字符串“7e-10”(科学计数法); 即执行了parseInt("7e-10"); 字符e不是十进制类型之后一起被截掉。
但是还存在下面的情况:当大于 1e-6 的数值不会转换为科学计数法。
parseFloat() 方法
对于这个方法来说,第一个出现的小数点是有效字符。如果有两个小数点,第二个小数点将被看作无效的。parseFloat() 会把这个小数点之前的字符转换成数字。这意味着字符串 "11.22.33" 将被解析成 11.22。
使用 parseFloat() 方法的另一不同之处在于,字符串必须以十进制形式表示浮点数,而不是用八进制或十六进制。该方法会忽略前导 0,所以八进制数 0102 将被解析为 102。对于十六进制数 0xA,该方法将返回 NaN,因为在浮点数中,x 不是有效字符。(注释:经测试,具体的浏览器实现会返回 0,而不是 NaN。)
String() 函数可以将任意类型的值转化成字符串。转化规则如下:
Boolean() 函数可以将任意类型的值转为布尔值。在条件判断时,除了undefined,null,false,NaN,'',0,-0,其他所有值都转为true,包括所有对象。
2)常见的隐式转化场景
a、比较运算(==、!=、>、<)、if、while需要布尔值地方
b、算术运算(+、-、*、/、%)
运算中其中一方为字符串,那么就会把另一方也转换为字符串;如果一方不是字符串或者数字,那么会将它转换为数字或者字符串。
那么对于除了加法的运算符来说,只要其中一方是数字,那么另一方就会被转为数字。
自动转换为布尔值:在需要布尔值的地方,就会将非布尔值的参数自动转为布尔值,系统内部会调用Boolean函数。除了undefined、null、false、+0、-0、NaN、"" 会被转化成false,其他都换被转化成true。
自动转换成字符串:遇到预期为字符串的地方,就会将非字符串的值自动转为字符串。具体规则是先将复合类型的值转为原始类型的值,再将原始类型的值转为字符串。常发生在+运算中,一旦存在字符串,则会进行字符串拼接操作。
自动转换成数值:除了+有可能把运算子转为字符串,其他运算符都会把运算子自动转成数值。null转为数值时,值为0 。undefined转为数值时,值为NaN。
4、== 和 ===区别
等于操作符用两个等于号( == )表示,如果操作数相等,则会返回 true。
由于JavaScript中存在隐式转换,等于操作符在比较中先进行类型转换,再确定操作数是否相等。规则如下:
如果两个都为简单类型,字符串和布尔值都会转换成数值,再比较是否相等;简单类型与引用类型比较,对象转化成其原始类型的值,再比较是否相等;两个都为引用类型,则比较它们是否指向同一个对象;null 和 undefined 相等;存在 NaN 则返回 false;
全等操作符用 3 个等于号( === )表示,只有两个操作数在不转换的前提下相等才返回 true。即类型相同,值也需相同。null 和 undefined 不相等。