导读
今天我们来认识一下js中的数据类型,数据之间的显示转换和隐式转换,还有一些如何来检测这些数据类型的方法。js中有7中数据类型,分别如下:
- undefined 类型
- null 类型
- string 字符串类型
- number 数字类型
- boolean 布尔值类型
- Symbol 类型
- object 类型
数据类型
undefined 类型
undefined是js中的一个特殊值,也是一个假值。一个声明过但是没有初始化的变量,js会自动给变量赋值undefined。
let name;
console.log(name) // undefined
有一个方法typeof 用来检测数据类型,但是这个方法有一个问题,请看下面:
let name;
console.log(typeof name) // undefined
console.log(typeof age) // undefined
并没有对age声明,但是返回值却是undefined, 所以我们要对我们的变量进行初始化,这样当使用typeof 检测变量时候,返回undefined就说明该变量没有声明,而不是声明了没有初始化
null 类型
null也是js中的一个特殊值,null表示一个空对象的指针,所以用typeof 检测返回object的原因。null也是一个假值,undefined是由null派生出来的,所有表面是相等的 null == undefined,但是null的用法和undefined不一样,如果我们要对一个变量进行对象赋值的时候,通常会先初始化一个null值,来表示这个变量将储存对象
boolean 类型
boolean是布尔值,有两个值true和false,区分大小写,所有True和Flase并不是布尔值。还可以显式将数据转换成boolean, 可以调用Boolean()函数,下面列举了不同数据类型转换boolean的规则
| 数据类型 | 转换true | 转换false |
|---|---|---|
| Boolean | true | false |
| String | 非空字符串 | "" (空字符串) |
| Number | 非零数值(包括无穷值) | NaN, 0 |
| Object | 任意对象 | null |
| Undefined | 不存在 | undefined |
Boolean()是显式转换,还有隐式转换,请看下面:
let message;
if(message) {}
// 在if语句这样写,message就会被隐式转换成Boolean类型来判断
Number 类型
number类型是使用IEEE 754 格式来表示整数和浮点数的,长度是64位,内存占8 Byte。
1. 整数可以用十进制,八进制和十六进制来表示
let a = 10 // 十进制 10
let b = 070 // 八进制 56
let c = 0xA // 十六制 10
2. 浮点数
let a = 1.1
let b = 0.1
let c = .1 // 不推荐
// 也可以用科学记数法来表示
let floatNum = 3.125e7; // 等于 31250000
3. 浮点数的计算可能会带来精度的丢失
例如:0.1 + 0.2 等于 0.300 000 000 000 000 04
但是 0.5 + 0.5 就不会有这样的事情
4. 数值的范围
// 最大值
Number.MAX_VALUE
1.7976931348623157e+308
// 最小值
Number.MIN_VALUE
5e-324
// 超出范围会转换成无穷值 Infinity, 可带正负符号
5. NaN
NaN 是一个特殊值, 表示不是一个数字
console.log(0/0); // NaN
console.log(-0/+0); // NaN
console.log(-0/NaN); // NaN
js 提过了一个isNaN()函数, isNaN()会把传入的参数尝试转换成数值,如果可以转换成数值就返回false, 如果不能就返回true
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false,10 是数值
console.log(isNaN("10")); // false,可以转换为数值 10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值 1
6. 数值转换规则
js 提供了一个显式转换数值的函数 Number(), 转换规则如下:
- 数值,直接返回
- 布尔值, true 返回
- null, 返回0
- undefined, 返回NaN
- 字符串
- 字符串中只包含数值字符,包括数值字符前面的加号和减号(正负符号),将会以转换一个十进制数值返回,并且会会忽略数值符号前置的0
Number('123') // 123 Number('-123') // 123 Number('-00001') // -1- 字符串中只包含有效的浮点数型的数值字符,返回浮点数的数值,同样也是忽略前置0,如果小数点后的数值都是0,则也会忽略
Number('1.1') // 1.1 Number('123.0000') // 123 Number('123.001') // 123.001- 字符串只包含有效的十六进制字符串,则会转换成该十六进制相对应的十进制数值
Number('0xA') // 10- 字符串只是空字符串,则返回0
- 字符串中包含了除上述字符串以外的字符串,则都返回NaN
- 对象,先调用valueOf()方法,然后依照上述方法进行转换,如果转换结果是NaN,那么就调用toString(), 再依照上述方法进行转换
// 1. 对象{}
Number({}) // NaN
var a = {}
a.valueOf() // {} 还是对象本身
a.toString() // "[object Object]"
// 所以返回NaN
// 2. 数组 []
Number([]) // 0
var a = []
a.valueOf() // [] 本身
a.toString() // "" (空字符串)
// 所以返回0
7. parseInt()
parseInt(string, radix) 解析一个字符串并返回指定基数的十进制整数, radix 是2-36之间的整数,表示被解析字符串的基数。
通常用来将字符串转换成整数,该函数接受两个参数,一个是要转换的数,二是转换成什么样的进制数。 规则如下:
- 如果第一个字符不是数值或者+、-符号,则直接返回NaN
- 如果第一个字符是数值或者+、-符号,则继续检索下一个字符,直到字符串末尾或者碰到非数值字符
- 第二个参数是转换成相应的进制数,有效的是2~36位,默认十进制数
- 如果第一个字符是数值字符,parseInt()也会自动识别
parseInt('123bbb') // 123
parseInt('12.1') // 12 因为小数点不是有效的数值字符
let num1 = parseInt("10", 2); // 2,按二进制解析
let num2 = parseInt("10", 8); // 8,按八进制解析
let num3 = parseInt("10", 10); // 10,按十进制解析
let num4 = parseInt("10", 16); // 16,按十六进制解析
let num3 = parseInt("0xA"); // 10,解释为十六进制整数
let num4 = parseInt(22.5); // 22
let num5 = parseInt("70"); // 70,解释为十进制值
let num6 = parseInt("0xf"); // 15,解释为十六进制整数
8. parseFloat()
parseFloat和parseInt功能类似,区别在于(1)第一次出现的小数点是有效的,第二个出现的小数点是无效的,(2)忽略前置0
let num1 = parseFloat("1234blue"); // 1234,按整数解析
let num2 = parseFloat("0xA"); // 0
let num3 = parseFloat("22.5"); // 22.5
let num4 = parseFloat("22.34.5"); // 22.34
let num5 = parseFloat("0908.5"); // 908.5
let num6 = parseFloat("3.125e7"); // 31250000
String 类型
一般情况下有三种方式定义变量是字符串
let name = "abc" // 双引号
let name1 = 'abc' // 单引号
let name2 = `abc` // 模版字面量
1. 字符字面量
| 字符字面量 | 含义 |
|---|---|
| \n | 换行 |
| \t | 制表 |
| \b | 退格 |
| \r | 回车 |
| \f | 换页 |
| \ | 反斜杠(\) |
| ' | 单引号 |
| " | 双引号 |
| ` | 反引号 |
| \xnn | 以十六进制编码 nn 表示的字符(其中 n 是十六进制数字 0~F),例如 \x41 等于 "A" |
| \unnnn | 以十六进制编码 nnnn 表示的 Unicode 字符(其中 n 是十六进制数字 0~F),例如 \u03a3 等于希腊字符 "Σ" |
2. 特点
js中字符串一点创建了就不能修改,要修改某个字符串变量的值,就必须销毁原来的字符串,将包含新值的新的字符串保存到该变量
3. 转换为字符串
- 使用toString(), 默认情况下转换成十进制的字符串,可以自定义有效基数的字符串
let num = 10;
num.toString() // 10
// 传递参数
num.toString(2) // '1010'
num.toString(8) // '12'
num.toString(16) // 'a'
- 调用String() 函数,规则如下
- 如果有toString()方法,就调用该方法(不传参)
- 如果是null, 返回"null"
- 如果是undefined, 返回"undefined"
- 使用一元操作符+
let str = 10 + '' + 123 // "10123"
4. 模版字符串
ES6新增语法,使用反引号引起来的字符串,并且内部可以使用插值符号进行变量引用。任何js表达式都可以作为插入值
let name = `h`
let name1 = `${name}i` // hi
let name2 = `${name === 'h' ? 'x': 'y'}i`
// 所有的插入的值都会使用toString()方法来转换成字符串
let obj = {
toString(){
return 1
}
}
let name = `${obj}`
console.log(name) // 1
Symbol 类型
Symbol是符号,ES6新增的数据类型,符号是原始数据类型,符号实例是唯一的,不可改变,符号的用途是保证对象属性的唯一性,避免对象属性冲突,因为是原始数据,所有typeof 操作符返回的结果也是"symbol"
let s = Symbol()
console.log(typeof s) // "symbol"
let obj = {
[s]: 'str'
}
console.log(obj[s]) // 'str'
Symbol有很多种用法,后面会单独来讲解
Object 类型
js 中对象就是一组数据和功能的集合,可以给对象添加属性和方法。
let obj = {
name: 'hi',
getName: function(){
return this.name
}
}
数据转换
显式转换
String(), Number(), parseInt(), parseFloat(), Boolean()
String()
转换规则:
- 基本数据类型
- 如果有toString()方法,则调用toString()返回数据
- 如果是null, 返回"null"
- 如果是undefined, 返回"undefined"
- 引用类型
- 先调用toString()方法,如果返回的是基本数据类型,则使用上述基本类型规则转换
- 如果返回的不是基本数据类型,则调用valueOf() 方法,如果返回的是基本数据类型,则使用上述基本类型规则转换
- 如果返回的不是,则抛出错误
Number()
转换规则:
- 如果是布尔值true和false, 则true返回1,false返回0
- 如果是数值,则直接返回
- 如果是null, 则返回0
- 如果是undefined, 则返回NaN
- 如果是字符串
- 如果字符串中包含数值字符,包括+、- 符号,则转换成十进制数
- 如果字符串中包含浮点数,则转换成相应的浮点数
- 如果字符串包含有效的十六进制格式如 "0xf" ,则会转换为与该十六进制值对应的十进制整数值。
- 如果字符串是空字符串,则返回0
- 如果字符串中包含除了上述以外的字符,则返回NaN
- 如果是对象,先调用valueOf方法,并按照上述的规则转换返回的值,如果转换结果为NaN,则调用toString()方法,再按照转换字符串的规则转换。
Boolean()
转换规则:
- 如果是布尔值true , 则返回true
- 如果是布尔值false , 则返回false
- 如果是非空字符串,则返回true
- 如果是空字符串,则返回false
- 如果是非零数值,则返回true
- 如果是0, NaN, 则返回false
- 如果是对象,则返回true
- 如果是null, 则返回false
- 如果是undefined, 则返回false
隐式转换(通常称为强制类型转换)
1. 只判断变量
隐式使用Boolean()转换规则
var name = ''
if(name) {
// 不会执行
}
var age = name ? '1' : '2'
2. 关系运算符
分为两种情况,一种是关系操作符,一个值相等操作符
2.1 关系操作符(>、<、>=、<=)
规则如下:
- 如果两边都是数值,则进行数值比较
- 如果两个都是字符串,则逐个比较对应的字符串编码
- 如果有一个是数值,则将另一个转换成数值,再进行比较
- 如果有一个是对象,则调用valueOf()方法,取的的结果在根据上述规则比较,如果没有valueOf()方法,则调用toString()方法,取的的结果在根据上述规则比较
- 如果有一个是布尔值,则将其转换成数值进行比较
2.2 相等操作符
规则如下:
- 如果有一个是布尔值,则将其转换成数值进行比较,true为1, false为0
- 如果有一个是字符串,另一个是数值,则将字符串尝试转换成数值,在进行比较
- 如果一个是对象,另一个不是,则调用对象上的valueOf()方法获取原始值,再根据上述规则比较,如果valueOf 获取到的值不是基本数据类型,则调用toString()方法获取值,再根据上述规则比较
- null 和 undefined 值相等,不进行任何数据转换
- 如果有一个是NaN,则直接返回false, 如果另一个也是NaN,也直接返回false, 根据规则,NaN和任何数据都不相等,包括自身
- 如果两个都是引用类型对象,则比较两个地址是否指向同一个对象,如果是,则返回true, 反之返回false
检测方法
1. typeof
console.log(typeof "helloworld") ------------------>"string"
console.log(typeof 123) ------------------>"number"
console.log(typeof [1,2,3]) ------------------>"object"
console.log(typeof new Function()) ------------------>"function"
console.log(typeof new Date()) ------------------>"object"
console.log(typeof new RegExp()) ------------------>"object"
console.log(typeof Symbol()) ------------------>"symbol"
console.log(typeof true) ------------------>"true"
console.log(typeof null) ------------------>"object"
console.log(typeof undefined) ------------------>"undefined"
console.log(typeof 'undefined') ------------------>"string"
2. instanceof
[1,2,3] instanceof Array -------->true
new Date() instanceof Date -------->true
new Function() instanceof Function -------->true
new Function() instanceof function -------->false
null instanceof Object -------->false
3. 对象原型链判断方法: Object.prototype.toString.call()
console.log(Object.prototype.toString.call("123")) -------->[object String]
console.log(Object.prototype.toString.call(123)) -------->[object Number]
console.log(Object.prototype.toString.call(true)) -------->[object Boolean]
console.log(Object.prototype.toString.call([1, 2, 3])) -------->[object Array]
console.log(Object.prototype.toString.call(null)) -------->[object Null]
console.log(Object.prototype.toString.call(undefined)) -------->[object Undefined]
console.log(Object.prototype.toString.call({name: 'Hello'})) -------->[object Object]
console.log(Object.prototype.toString.call(function () {})) -------->[object Function]
console.log(Object.prototype.toString.call(new Date())) -------->[object Date]
console.log(Object.prototype.toString.call(/\d/)) -------->[object RegExp]
console.log(Object.prototype.toString.call(Symbol())) -------->[object Symbol]