前言
在js中,当运算符在运算时,如果两边数据不统⼀,CPU就⽆法计算,这时我们编译器会⾃动将运算符两边的数据做⼀个数据类型转换,转成⼀样的数据类型再计算。这种⽆需程序员⼿动转换,⽽由编译器⾃动转换的⽅式就称为隐式转换。对于即将面试的小伙伴,小编在这里祝愿大家offer拿到手软.
一. js数据类型
基本数据类型(也就是原始值):
Undefined、Null、Boolean、Number、String、Symbol(es6)、BigInt(es10)
引用数据类型
Object Array Function Date
我们说万物皆对象,所以他们都是Object
二.类型转换
数据类型间的转换可分为:
- 原始值间的转换:转换为Boolean、Number、String
- 原始值转换为对象:转换为Object
- 对象转换为原始值:有两种转换方式
1.原始值转换
字符串的转换ToString
原始值需要借助内建类型,String()来将一个非字符串类型强制转换为string,String()转换的过程是由语言规范ToString抽象操作处理的.
参数类型 | 结果 |
---|---|
Undefined | "undefined" |
Null | "null" |
Boolean | 如果参数是 true,返回 "true"。参数为 false,返回 "false" |
Number | 又是比较复杂,可以看例子 |
String | 返回与之相等的值 |
布尔值的转换ToBoolean
原始值需要借助内建类型(原生类型), Boolean() 来将一个非字符串类型强制转换为 boolean , Boolean() 转换的过程是由语言规范 ToBoolean 抽象操作处理的。
参数类型 | 结果 |
---|---|
false | false |
undefined | false |
null | false |
+0 | false |
-0 | false |
NaN | false |
'' | false |
除了这六种转为false, 其余的都是true.
数值的转换ToNumber
原始值需要借助内建类型(原生类型), Number() 来将一个非字符串类型强制转换为 number , Number() 转换的过程是由语言规范 ToNumber 抽象操作处理的。
参数类型 | 结果 |
---|---|
Undefined NaN | |
Null | +0 |
Boolean | 如果参数是 true,返回 1。参数为 false,返回 +0 |
Number | 返回与之相等的值 |
String | 这段比较复杂,看例子 |
Number 来转换一个字符串,会将其转为一个整数或浮点数,会忽略所有前导的 0, 如果有一个字符不是数字,结果都会返回 NaN。
2.对象转原始值
js有俩个不同的方法来执行转换,一个是toString,一个是valueOf. (真实暴露出来的)
Object.prototype.toString方法可以返回[[class]]内部属性
而js下的很多类根据自己的特点,定了更多版本的toString.
- 数组的toString返回一个字符串,逗号隔开.
- 函数的toString方法返回源代码字符串.
- 日期的toString方法返回一个可读的日期和时间字符串.
- RegExp的toString返回一个表示正则表达式直接量的字符串.
valueOf表示对象的原始值,默认的valueOf返回对象本身,日期会返回毫秒数.
是利用 ToPrimitive 方法,输入一个值,返回一个基本类型的值。
ToPrimitive(input[, PreferredType])
他接收俩个参数,第一个参数是input,表示要处理的值
第二个参数是PreferredType,表示希望转成的类型,可以是Number,String
如果不传入第二个PreferredType,如果 input 是日期类型,相当于传入 String,其余都是传入 Number。
如果传入的 input 是 null, undefined, string, number, boolean 会直接返回该值。
如果是 ToPrimitive(obj, Number).
- 如果obj为基本类型,直接返回
- 否则,调用valueOf方法,如果返回一个原始值,则Javascript将其返回.
- 否则,调用toString 方法,如果返回一个原始值,则 JavaScript 将其返回。
- 否则,JavaScript 抛出一个类型错误异常。
如果是 ToPrimitive(obj, String),处理步骤如下:
- 如果 obj为 基本类型,直接返回
- 否则,调用 toString 方法,如果返回一个原始值,则进一步转换为字符串返回。
- 否则,调用 valueOf 方法,如果返回一个原始值,结果同上。
- 否则,JavaScript 抛出一个类型错误异常。
2.1 valueOf 和 toString的返回值解析
控制台输出 Object.prototype,就可以看到 valueOf() 和 toString() 。而所有对象继承自Object,因此所有对象都继承了这两个方法。对 Js 常见的内置对象:基本包装类型(Number、String、Boolean)、单体内置类型(global、Math)、Date、Array、Function、RegExp,分别使用 toString() 和 valueOf() 得到的返回结果,做进一步分析。
valueOf():
var num = new Number('123');
num.valueOf(); // 123
var str = new String('12323adc');
str.valueOf(); // 12323adc
var bool = new Boolean('abc')
bool.valueOf(); // true
// 2. Date 类型返回一个内部表示:1970年1月1日以来的毫秒数
var date = new Date();
date.valueOf(); // 1608784980823
// 3. 返回对象本身
var obj = new Object({});
obj.valueOf() === obj; // true
var arr = new Array();
arr.valueOf() === arr; // true
var reg = new RegExp(/a/);
reg.valueOf() == reg; // true
var func = function() {};
func.valueOf() == func; // true
// 单体内置类型
global.valueOf() == global; // true
Math.valueOf() == Math; // true
toString() : 作用是返回一个反应该对象的字符串:
// 1. 基本包装类型返回原始值
var num = new Number('123abc');
num.toString(); // 'NaN'
var str = new String('123abc');
str.toString(); // '123abc'
var bool = new Boolean('abc');
bool.toString(); // 'true'
// 2. 默认的 toString()
var obj = new Object({});
obj.toString(); // "[object Object]"
global.toString() // "[object Window]"
Math.toString(); // "[object Math]"
// 3. 类自己定义的 toString()
// Date类型转换为可读的日期和时间字符串
var date = new Date();
date.toString(); // "Wed Oct 11 2017 08:00:00 GMT+0800 (中国标准时间)"
// 将每个元素转换为字符串
var arr = new Array(1,2);
arr.toString(); // '1,2'
// 返回表示正则表达式的字符串
var reg = new RegExp(/a/);
reg.toString(); // "/a/"
// 返回这个函数定义的 Javascript 源代码字符串
var func1 = function () {}
func1.toString(); // "function () {}"
function func2() {}
func2.toString(); // "function func2() {}"
2.2类型装换表分析和归纳
3.显示转换
人为的调用函数去转换:
- 转换为字符串: toString() 和 String
- 转换为数值: Number() , parseInt() , parseFloat()
- 转换为布尔值: Boolean()
- 转换为对象: Object()
String(false) // "false" 布尔值转换为字符串
Number("123") // 123 字符串转换为数值
Boolean([]) // true 对象类型转换为布尔值
Object(123) // new Number(123)
4.隐式转换
常见的隐式转换:
- 逻辑语句的类型转换: 当使用if , while , for时, 隐式转换为布尔值
- 逻辑表达式:
- ! 逻辑非,隐式转换为布尔值,并取反, !!俩次逻辑非,隐式转换为布尔值;
- || 和 && 会将非布尔值会将非布尔值操作数,隐式转换为布尔值,在判断;
- 算数表达式:
- 递增递减++ --,一元加减 +a、- a(结果的符号取反),二元 -,乘法,除法,求模,隐式转换为 Number;
- +运算符:
不同类型间的转换规则
如果其中一个操作符是对象,则进行对象到原始值的转换(这里是通过 toString 方法获取);
进行了对象到原始值的转换后,如果其中一个操作数是字符串,则另一个操作数也会转换成字符串,再进行连接;
否则两个操作数都转换为数字(或者NaN),然后进行加法操作。
- == 运算符: 具体看例子
5.隐式转换的具体例子
- 通过字符串连接符转换
// + 字符串连字符
console.log(typeof(1 + '123')); // string '1123'
console.log(typeof(true + '123')); // string 'true123'
console.log(typeof(null + '123')); // string 'null123'
console.log(typeof(NaN + '123')); // string 'NaN123'
console.log(typeof(undefined + 'str')) // string 'undefinedstr'
// --------------------------------
console.log([] + '123') // '123'
console.log([1,2,3] + '123') // '1,2,3123'
console.log({} + '123')
// '[object Object]123' 这里 + 代表字符串连字符而不是算数运算符,因此隐式转换:
// 通过toString() , 返回[object Object]
// 最后由字符串连接符连接
console.log({a:1} + '123') // '[object Object]123'
- 通过算数运算符转换
// +
console.log(123 + true); // 123 + 1
console.log(123 + false); // 123 + 0
console.log(123 + NaN); // NaN
console.log(123 + undefined); // 123 + NaN => NaN
console.log(123 + null); // 123 + 0
// ---------------------------------
console.log(123 + {}); // '123[object Object]'
console.log(123 + {a:'1'}); // '123[object Object]'
console.log(123 + [1]); // '1231'
console.log(123 + [1,2,3]); //'1231,2,3'
console.log([] + 123); // '123'
// 下面 + 是以字符串连接符来看的
注释:
1. 如[] + 123 时 , 隐式转换会先走valueOf() , 返回 这个数组本身
2. 接着会走toString() 将数组转换成 ''
3. 最后 '' + 123 , 结果才为字符串 '123'
// - 算数运算符 , 其他类型全部转换成数字型 , 忘了的可以去查看上面的表格
console.log(123 - true); // 123 - 1
console.log(123 - false); // 123 - 0
console.log(123 - NaN); // NaN
console.log(123 - undefined); // 123 - NaN => NaN
console.log(123 - null); // 123 - 0
// ---------------------------------
console.log([] - 123); // 0 - 123 => -123
console.log(123 - {}); // NaN
console.log(123 - {a:'1'}); // NaN
console.log(123 - [1]); // 122
console.log(123 - [1,2,3]); // NaN
- 通过关系运算符
console.log('' == 0);//true
console.log([] == 0);//true
console.log(false == 0);//true
console.log({} == 0);//false
console.log(NaN == 0);//false
console.log(undefined == 0);//false
console.log(null == 0);//false
//特殊情况:无视规则
console.log(NaN == NaN);//false
console.log(null == undefined);//true
console.log(null === undefined);//false null--object undefined----undefined
//----------------------------------------------------------------------------------
console.log('2' > 10);//false
console.log('2' > '10');//true
// 注解:
// '2' > 10 比较的时候 会把 '2' 转换成 2 , 2 > 10 不用想肯定为false
// '2' > '10' 单个字符串比较是以uniCode码比较的
// charCodeAt 可以将其转换为uniCode码
console.log('2'.charCodeAt());//50
console.log('10'.charCodeAt());//49
console.log('a' > 'b');//false
console.log('a'.charCodeAt());//97
console.log('b'.charCodeAt());//98
console.log('z'.charCodeAt());//122
// a - z 97 - 122
console.log('a'>'A')//
console.log('A'.charCodeAt());//65
console.log('Z'.charCodeAt());//90
//A-Z 65-90
//A<Z<a<z
// 长条字符串从左到右依次比较
console.log('abc' > 'b');//false
// 多个字符串比较从左往右依次单个比较(这里注意不会比完有一个不一样就比出结果了)
// 第二个字符 b > a ,所以最后的结果就是 'abc' >'aad'
console.log('abc' > 'aad');//true
---------------------------------------------------------------------------------------------------------------------------------
至此,本篇也算是完结了,希望小伙伴们看的这篇文章有不一样的收获.文章可能有点长,希望小伙伴们可以坚持看完,小编相信坚持后的你肯定是最自信的~
喜欢小编的可以点赞哦,关注小编不迷路~