1. 获取数据类型
js中的数据类型
-
原始类型:String,Number, Boolean,null, undefined, BigInt,Symbol
-
对象类型: Object
包括很多通过 new keyword 创建的数据,比如 new Object,new Array,new Map,new Set
获取类型的方法
- typeof
- instanceof
- constructor(慎用)
- Object.prototype.toString(推荐)
-
typeof :7 种原始类型,使用 typeof 运算符检查
console.log('string',typeof '') console.log('number',typeof 123) console.log('boolean',typeof false) console.log('undefined',typeof undefined) console.log('bigint',typeof BigInt(123)) console.log('symbol',typeof Symbol()) console.log('null',typeof null) //异常:打印结果是object -
instanceof: 检查 Object 数据类型。构造函数推荐使用
instanceof检测。function Person() {}; const a = new Person(); // 判断Object.prototype是否在a的原型链上 a instanceof Object // true a instanceof Person // true -
constructor: 检测某个实例属否属于这个类的
-
语法:
实例.constructor === 类 -
返回值:属于返回
TRUE,不属于返回FALSE[1,2,3].constructor === Array; // true -
弊端:容易被篡改
Array.prototype.constructor = {}; const arr = new Array(1,2,3); arr.constructor === Array; // false
-
-
Object.prototype.toString(推荐)
对于
Object.prototype.toString()方法,会返回一个形如"[object type]"的字符串。如果此数据类型的
toString()方法未被重写,就会返回如上面形式的字符串。({}).toString(); // => "[object Object]" Math.toString(); // => "[object Math]"但是,大多数数据类型,toString() 方法都是重写了的,如下:
console.log('boolean', (false).toString()); //boolean 'false' console.log('number', (123).toString()); //number '123'需要用 call方法来调用。
console.log('string',Object.prototype.toString.call('')); console.log('number',Object.prototype.toString.call(123)); console.log('boolean',Object.prototype.toString.call(false)); console.log('undefined',Object.prototype.toString.call(undefined)); console.log('bigint',Object.prototype.toString.call(BigInt(123))); console.log('symbol',Object.prototype.toString.call(Symbol())); console.log('null',Object.prototype.toString.call(null)); console.log('object',Object.prototype.toString.call({}));
2.类型转换
指将数据从一种类型转换到另一种类型的过程。类型转换分为两类:
显式的类型转换:就是你可以在代码中看到的类型由一种转换到另一种,比如Number(值)、String(值)...隐式的类型转换:多是某些其他运算可能存在的隐式副作用而引发的类型转换。比如+、-...
2.1 显式类型转换
- 常用的显式类型转换方法有
String、toString、Boolean、Number、parseInt、parseFloat等等
2.2 隐式类型转换
-
隐式转换的场景:
- 算术运算
- 单目运算符+
- if条件表达式转换为布尔
- !运算符转为布尔
- ==比较
- 比较运算符>、<、≥、≤
-
== 隐式转换规则
== 和 === 的区别在于,粗略相等 检查的是允许类型转换情况下的值的相等性,而 严格相等 检查不允许类型转换情况下的值的相等性;
- 字符串和数字比较, 会把字符串转换成数字
- 有布尔值的, 把布尔值转换成数字
- 对象和标准基本类型之间的相等比较, 调用对象的toPrimitive
- 在 == 中,undefined == undefined或者null,不等于其他任何值,null同理;
- NaN不等于任何值包括NaN
NaN 是唯一一个不等于自身的值,所以会用 值 !== 值 来判断isNaNNaN === NaN // false;
2.3 类型转换
类型转换中主要涉及到四种转换:
- 将值转为数字,ToNumber()。
- 将值转为字符串,ToString()。
- 将值转为布尔值,ToBoolean()
- 将值(复杂类型)转为原始值,Symbol.toPrimitive()。
2.3.1 ToString
通过ToString将值转换为字符串
-
根据参数类型进行下面转换:
参数 结果 undefined 'undefined' null 'null' 布尔值 转换为'true' 或 'false' 数字 数字转换字符串,比如:1.765转为'1.765' 字符串 无需转换 对象 先进行 ToPrimitive(obj, String)转换得到原始值,在进行ToString转换为字符串 //----------- 运算 // 1. 加法运算符 console.log(false + '123') //----------- == // 2. == !object(非对象) && !number(非数字) && !boolean(非布尔类型) console.log('abc' == null) console.log('abc' == undefined) // 3. == object console.log('123' == [123]) 1、由于[123]是对象类型,故先进行原始类型转换,ToPrimitive(input, String)运算。 2、继续执行toString方法,[123].toString(),返回"123",是原始值。 3、转换为原始值后再进行toString运算,"123" 就转换为 '123'。 4、故最终的结果为 '123' == '123' //true
2.3.2 ToNumber
-
根据参数类型进行下面转换:
参数 结果 undefined NaN null 0 布尔值 true转换1,false转换为0 数字 无需转换 字符串 有字符串解析为数字,例如:‘324’转换为324,‘qwer’转换为NaN, ''转化为数字0 对象 先进行 ToPrimitive(obj, Number)转换得到原始值,在进行ToNumber转换为数字 //---------- 运算 // 1. - / * console.log(123 / '123') console.log(123 - '123') console.log(123 * '123') // 2. + !string(非字符串) console.log(123 + false) console.log(123 + null) //---------- == // 3. == !object(非对象) console.log(123 == false) // 4. == object console.log(123 == [123]) 1、由于[123]是对象类型,故先进行原始类型转换,ToPrimitive(input, Number)运算。 2、所以会执行valueOf方法,[123].valueOf(),返回的还是[123]对象,不是原始值。 3、继续执行toString方法,[123].toString(),返回"123",是原始值。123 4、转换为原始值后再进行ToNumber运算,"123" 就转换为 123。 5、故最终的结果为 123 === 123
2.3.3 ToBoolean
| 参数 | 结果 |
|---|---|
| undefined | false |
| null | false |
| 布尔值 | 无需转换 |
| 数字 | 0、-0、NaN为false,其他的为true |
| 字符串 | '' 为false,其他为true |
| 对象 | true |
2.3.4、通过ToPrimitive将对象转换为原始值
-
Symbol.toPrimitive(input, PreferredType?)
- input是要转换的值
- PreferredType是可选参数,可以是Number或String类型。
1. 如果有Symbol.toPrimitive()方法,优先调用并返回
var obj = { [Symbol.toPrimitive] () { return 3; }, valueOf () { return 2; }, toString () { return 1; } } // obj == 3 true2. 如果没有Symbol.toPrimitive()方法,PreferredType被标记为Number,则会进行下面的操作流程来转换输入的值。
1、如果输入的值已经是一个原始值,则直接返回它 2、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,如果valueOf()方法的返回值是一个原始值,则返回这个原始值。 3、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。 4、否则,抛出TypeError异常。3. 如果没有Symbol.toPrimitive()方法,PreferredType被标记为String,则会进行下面的操作流程来转换输入的值。
1、如果输入的值已经是一个原始值,则直接返回它 2、否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。 3、否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,如果valueOf()方法的返回值是一个原始值,则返回这个原始值。 4、否则,抛出TypeError异常。4. 如果没有Symbol.toPrimitive()方法,省略preferedType
1、该对象为Date类型,则PreferredType被设置为String 2、否则,PreferredType被设置为NumbervalueOf方法和toString方法解析
-
Object.prototype是所有对象原型链顶层原型,所有对象都会继承该原型的方法,故任何对象都会有valueOf和toString方法。
-
valueOf
-
Number、Boolean、String这三种构造函数生成的基础值的对象形式,通过valueOf转换后会变成相应的原始值。如:
var num = new Number('123'); num.valueOf(); // 123 var str = new String('12df'); str.valueOf(); // '12df' var bool = new Boolean('fd'); bool.valueOf(); // true -
Date这种特殊的对象,其原型Date.prototype上内置的valueOf函数将日期转换为日期的毫秒的形式的数值。
var a = new Date(); a.valueOf(); // 1515143895500 -
除此之外返回的都为this,即对象本身:
var a = new Array(); a.valueOf() === a; // true var b = new Object({}); b.valueOf() === b; // true
-
-
toString
Number、Boolean、String、Array、Date、RegExp、Function这几种构造函数生成的对象,通过toString转换后会变成相应的字符串的形式,因为这些构造函数上封装了自己的toString方法。如:
var num = new Number('123sd'); num.toString(); // 'NaN' var str = new String('12df'); str.toString(); // '12df' var bool = new Boolean('fd'); bool.toString(); // 'true' var d = new Date(); d.toString(); // "Wed Oct 11 2017 08:00:00 GMT+0800 (中国标准时间)" var func = function () {} func.toString(); // "function () {}"Array转换(⚠注意)
var arr = [1,2]; arr.toString(); // '1,2'除这些对象及其实例化对象之外,其他对象返回的都是该对象的类型,都是继承的Object.prototype.toString方法。
var obj = new Object({}); obj.toString(); // "[object Object]" Math.toString(); // "[object Math]"
1.4 常见变量转换表
| 原始值 | 转为数字 | 转为字符串 | 转为布尔 |
|---|---|---|---|
| false | 0 | "false" | false |
| true | 1 | "true" | true |
| 0 | 0 | "0" | false |
| 1 | 1 | "1" | true |
| "0" | 0 | "0" | true |
| "000" | 0 | "000" | true |
| "1" | 1 | "1" | true |
| NaN | NaN | "NaN" | false |
| Infinity | Infinity | "Infinity" | true |
| -Infinity | -Infinity | "-Infinity" | true |
| "" | 0 | "" | false |
| "20" | 20 | "20" | true |
| "a" | NaN | "a" | true |
| [] | 0 | "" | true |
| [10,20] | NaN | "10,20" | true |
| function(){} | NaN | "function(){}" | true |
| { } | NaN | "[object Object]" | true |
| null | 0 | "null" | false |
| undefined | NaN | "undefined" | false |
1.5 实践
-
对象和数字/布尔值比较
对象和布尔值进行比较时,对象先ToPrimitive(input, Number)运算,然后再转换为数字,布尔值直接转换为数字
{} == 1; 1、由于{}是对象类型,故先进行原始类型转换,ToPrimitive(input, Number)运算。 2、所以会执行valueOf方法,({}).valueOf(),返回的还是{}对象,不是原始值。 3、继续执行toString方法,({}).toString(),返回"[object Object]",是原始值。 4、转换为原始值后再进行ToNumber运算,"[object Object]"就转换为NaN。 5、true转换为数字1。 故最终的结果为 NaN == 1[] == 0; 1、由于[]是对象类型,故先进行原始类型转换,ToPrimitive(input, Number)运算。 2、所以会执行valueOf方法,([]).valueOf(),返回的还是[]对象,不是原始值。 3、继续执行toString方法,([]).toString(),返回"",是原始值。 // 数组中的toString()方法会被改写 4、转换为原始值后再进行ToNumber运算,""就转换为0。 5、故最终的结果为 0 == 0 -
对象和字符串比较
对象和字符串进行比较时,对象先ToPrimitive(input, Number)运算,然后再转换为字符串,然后两者进行比较。
[1,2,3] == '1,2,3' 1、由于[]是对象类型,故先进行原始类型转换,ToPrimitive(input, String)运算。 3、继续执行toString方法,([]).toString(),返回"1,2,3",是原始值。 // 数组中的toString()方法会被改写 4、转换为原始值后再进行ToString运算,"1,2,3"就转换为"1,2,3"。 故最终的结果为 '1,2,3' == '1,2,3' -
字符串和 数字 比较
字符串和数字进行比较时,字符串转换成数字,二者再比较。
'1' == 1 // true -
字符串和布尔值 比较
字符串和布尔值进行比较时,二者全部转换成数值再比较
'1' == true; // true -
布尔值和数字比较
布尔值和数字比较时, 布尔转为数字, 二者比较
true == 1 // true