目录
- 一、什么是隐式转换?
- 二、转换规则
- 2.1 基本数据类型
- 2.1.1将值转为字符串
- 2.1.2将值转为数字(Number()函数)
- 2.1.3将值转为布尔值(Boolean()函数)
- 2.2 引用数据类型
- 2.2.1 引用数据类型互相比较
- 2.2.2 引用数据类型与基本数据类型比较
- 2.3 特殊1:逻辑非与关系运算符同时出现
- 2.4特殊2:`+`陷阱
- 2.4.1字符串连接符(有时会被浏览器认为一元`+`运算)
- 2.4.2加法运算
- 总结
一、什么是隐式转换?
定义:由编译器自动完成类型转换的方式就称为隐式转换。
二、转换规则
2.1 基本数据类型
2.1.1将值转为字符串
字符串连接符+ 使用这一规则。(只要+两边出现了字符串就是字符串连接符。)编译器将非string类型的值转为string类型,然后再将其拼接成一个新的字符串。
const test = 1 + '0' + true + undefined + null;
console.log(test); // 10trueundefinednull
console.log(typeof test); // string
2.1.2将值转为数字(Number()函数)
自增/自减运算符,算数运算符,关系运算符使用这一规则。 下表列出将其他类型的值转换为数字的情况:
序号 | 其他类型 | 转换为number类型后的值 |
1 | undefined | NaN |
2 | null | 0 |
3 | boolean |
|
4 | string | left-aligned 空字符串 |
这里对关系运算符中的几种情况进行说明: (1)字符串与字符串比较
比较方法(> < >= <= !=):通过依次比较字符串中每个字符所对应的unicode的值,若比较过程中能得出结果,直接返回结果并且不再比较后面的字符。 通过字符串的charCodeAt()方法可以查看每个字符的unicode。 该方法的用法及细节请参考链接: MDN > String.prototype.charCodeAt()
- 例1
console.log('a2c' > 'ab3'); // false
// 分析
console.log('a2c'.charCodeAt()); // 97
console.log('ab3'.charCodeAt()); // 97
// 不能得出结果,继续比较
console.log('a2c'.charCodeAt(1)); // 50
console.log('ab3'.charCodeAt(1)); // 98
// 得出结果不再比较
- 例2
// 字符串比较1
console.log('bA'>'b'); // true
// 字符串比较2
console.log('bA'<'b'); // false
// 分析
console.log('bA'.charCodeAt()); // 98
console.log('b'.charCodeAt()); // 98
// 不能得出结果
console.log('bA'.charCodeAt(1)); // 65
console.log('b'.charCodeAt(1)); // NaN
console.log('b'.charCodeAt()); // 98
这里可以看出,当比较的字符串长度不同,并且公共长度的字符比较不能得出结果时,比较的是字符串的长度,来得出结果的。(个人推测,若观点有误,请指正!)
比较方法(==):只有两个相同的字符串比较才为true。
(2)null 与undefined
序号 | 关系式 | 结果 |
1 | undefined == undefined ; | true |
2 | null== null; | true |
3 | undefined == null; | true |
Javascript规范中:规定null和 undefined 是相等的。null和 undefined都代表着无效的值。
(3)NaNNaN代表非数值的特殊值,用于指示某个值不是数字。NaN与任何类型的值比较都是false。
2.1.3将值转为布尔值(Boolean()函数)
逻辑非运算符!使用这一规则。编译器通过Boolean()函数将非布尔类型的值转为布尔值。下表列出只需记住以下转为布尔值为false的5种情况即可,其余全为true:
序号 | 值 | 备注 |
1 | undefined |
|
2 | null |
|
3 | 0 |
|
4 | NaN |
|
5 | 空字符串:双引号 | 空格 |
2.2 引用数据类型
2.2.1 引用数据类型互相比较
比较的是引用数据类型指向的地址。
console.log([] == []);// false:两个空数组指向不同的地址
const a = [];
const b = a;
console.log(a == b); // true:数组a, 数组b指向相同的地址
2.2.2 引用数据类型与基本数据类型比较
引用数据类型都是object实例,都会继承object的方法,所以都有valueOf()和toString()方法。 转换规则:先使用valueOf()获取原始值,如果原始值不是number类型,使用toString()转换为string类型,再转换为number类型比较或计算。 引用数据类型的valueOf()转换
引用数据类型 | 使用 |
Number |
|
String |
|
Boolean |
|
Date |
|
Array, Math,RegExp, Function,Object | this,对象本身 |
常见内置对象的toString()转换规则
常见内置对象 | 使用 |
Array | 数组元素以逗号隔开的字符串 |
Function | 函数源代码的字符串 |
Object |
|
Math |
|
RegExp | 正则表达式的字符串值 |
常见内置对象的toString()转换测试
console.log([1, 2, 3, 4].toString()); // 1,2,3,4
console.log({ age: 18 }.toString()); // [object Object]
function func() { }
console.log(func.toString()); // function func() { }
console.log(Math.toString()); // [object Math]
const exp = new RegExp(',');
console.log(exp.toString()); // /,/
2.3 特殊1:逻辑非与关系运算符同时出现
逻辑非!的优先级高于关系运算符,所以优先转换为boolean类型,再进行关系比较。 例题:
console.log([] == !{}); // true
- 过程分析:
- 运算优先级:! > ==,!{}即false, 等式变为 [] == false
- []通过valueOf()转换为[]=>通过toString()转换为'',等式变为'' == false
- 将其转换为number类型,即:0 == 0,等式成立,结果为true
2.4特殊2:+陷阱
2.4.1字符串连接符(有时会被浏览器认为一元+运算)
(1)字符串与其他类型拼接不再赘述。 (2)在浏览器的控制台中直接打印:空对象+其他数据类型时
空对象 + 任意对象(不同浏览器出现不同结果)
- Chrome
- 每个{}都会按照valueOf -> toString的转换顺序变为字符串的[object Object]
- +两边出现了字符串,即为字符串拼接符。即:{} + {} -> '[object Object]' + '[object Object]' = '[object Object][object Object]'
- FireFox
- 浏览器会将{}认为是一个空的代码区块(而不是一个对象字面量)并忽略,即:+{}
- 一元+会触发强制类型转换。即:{} + {} -> +{} -> Number({}) = NaN
空对象 + 其他数据类型(对象类型除外)
这次所有的浏览器都会将{}认为是一个空的代码区块,即使用一元+将其他类型转换为number类型的值。
Chrome
FireFox
2.4.2加法运算
除string类型与引用数据类型之外的原始类型的才是加法运算 核心:将其他原始类型转换为number类型
console.log(1 + 1); // 2
console.log(1 + true); // 2
console.log(1 + null); // 1
console.log(1 + undefined); // NaN
console.log(true + null); // 1
console.log(true + undefined); // NaN
console.log(null + undefined); // NaN
总结
JS隐式转换规则以流程图形式呈现(字符串拼接符的隐式转换除外)