值类型转换
将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况;隐式的情况称为强制类型转换
类型转换发生在静态类型语言的编译阶段,而强制类型转换则发生在动态类型语言的运行时
ToString
字符串化规则
- null转换为"null"
- undefined转换为"undefined"
- true转换为"true"
- 数字的字符串化则遵循通用规则(极大和极小数字使用指数形式)
- 对于普通对象来说,除非自行定义,否则toString()返回内部属性[[Class]]的值,若有自己的toString()方法,则会调用该方法返回其他值
- 对数组来说,toString经过重新定义,将所有单元字符串化后再用“,”链接起来
- JSON.stringify()在将JSON对象序列化时也用到了ToString
JSON字符串化与toString()的效果基本相同,只不过序列化的结果总是字符串:JSON.stringify(42); // "42" JSON.stringify("42")//""42"" JSON.stringify(null)//"null" JSON.stringify(true)//"true"
- 所有安全的JSON值都可以用JSON.stringify()字符串化,安全的JSON指能够呈现为有效JSON格式的值
undefined,function,symbol和包括循环引用的对象都不符合JSON结构标准,无法处理他们
JSON.stringify()在对象中遇到undefined,function和symbol时会自动将其忽略,在数组中则会返回null。对包含循环引用的对象执行JSON.strigify()会出错
JSON.stringify(undefined); //undefined
JSON.stringify(function(){}); //undefined
JSON.stringify(
[1,undefined,function(){},4]
); //"[1,null,null,4]"
- 如果对含有非法JSON值的对象做字符串化,或者对象中的某些值无法被序列化时,就需要定义toJSON()方法来返回一个安全的JSON值(这个值会再通过JSON.stringfy()序列化)
ToNumber
转化规则
- true转换为1
- false转换为0
- undefined转换为NaN
- null转化为0
- 对象(包括数组)首先转换为相应的基本类型值,如果返回的是非数字的基本类型值,在根据上述规则进行强制转换为数字
为了把值转换为相应的基本类型值,会先检查该对象是否有valueOf()方法,没有就使用toString后的返回值,如果valueOf()和toString()均不返回基本类型值,会产生TypeError错误。
var c = [4,2];
console.log(Number(c)); //undefined
var a = {
valueOf: function () {
return "42"
},
toString: function () {
return "41"
}
}
var b = {
toString: function () {
return "41"
}
}
// console.log(Number(b)) //41
console.log(Number(a)) //42 (valueOf优先调用)
ToBoolean
假值
- undefined
- null
- false
- +0,-0和NaN
- ""
以上均为假值,假值列表意外的值都应该是真值(未明确定义)。
假值对象
假值对象时指在常规Javascript语法基础上自己创建了一些外来的值,强制类型转换为false。(如document.all)
而封装了假值的对象,并非假值对象,强制类型转换时仍视作一个对象来看,转为true
var a = new Boolean(false);
var b = new Number(0);
var c = new String("");
console.log(Boolean(a)); //true
console.log(Boolean(b)); //true
console.log(Boolean(c)); //true
真值
假值以外的值
表示假值的字符串强制类型转化仍视为非空字符串看待,转化为true
var a = "false"
var b = "0";
var c = "''";
var d = Boolean(a&&b&&c);
d; //true
显式强制类型转换
显式强制类型转化是那些显而易见的类型转换
字符串和数字之间的显式转换
- 除String()和Number()外,还有其他方法可以实现字符串和数字之间的显式转换
var a = 42;
var b = a.toString();
//toString()对a不适用,Javascript引擎自动为42创建一个封装对象,然后调用该对象的toString()方法
var c = "3.14"
var d = +c;
b; //"42"
d; //3.14
- 日期显式转换为数字
var timestamp = +new Date()
- 暂不研究~运算符
显式解析数字字符串
- 解析允许字符串中含有非数字字符,解析按从左到右的顺序,如果遇到非数字字符就停止,而转换不允许出现非数字字符,否则失败返回NaN
var a = "42"
var b = "42px"
Number(a); //42
parstInt(a); //42
Number(b); //NaN
parseInt(b); //42
- 解析非字符串
parseInt()先将参数强制类型转换为字符串再进行解析。
parseInt(1/0,19); //18
//转换为字符串后parse("Infinity",19)
//第一个字符是“I”,以19为基数时值为18,第二个字符不是一个有效的数字字符,解析到此为止。(19为基数时,有效范围为0-9,a-i)
显示转换为布尔值
- 显示强制类型转换为布尔值最常用的方法是!!,因为第二个!会把结果反转为原值
var a = "0";
var b = [];
var c = {};
var d = "";
var e = 0;
var f = null;
var g;
!!a; //true
!!b; //true
!!c; //true
!!d; //false
!!e; //false
!!f; //false
!!g; //false
隐式强制类型转换
字符串和数字之间的隐式强制类型转换
+运算符既能用于数字加法,也能用于字符串拼接
简单来说,如果+的其中一个操作数是字符串(或者可以隐式转换为字符串)则执行字符串拼接,否则执行数字加法
var a = "42"
var b = "0";
var c = 42;
var d = 0;
a + b ; // "420"
c + d ; // 42
var e = [1,2];//首先对其调用ToPrimitive抽象操作,再调用[[DefaultValue]],以数字作为上下文
var f = [3,4];
e + f ; //"1,23,4"
布尔值到数字的隐式强制类型转换
function onlyOne(){
var sum = 0;
for(var i=0;i<arguments.length;i++){
if(arguments[i]){
sum += arguments[i];
}
}
}
var a = true;
var b = false;
onlyOne(b,a); //true
onlyOne(b,a,b,b); //true
onlyOne(b,a,b,b,a) //false
隐式强制类型转换为布尔值
- if(..)语句中的条件判断表达式
- for(..;..;..)语句中的条件判断表达式
- while(..)和do..whilee(..)循环中的条件判断表达式
- ?:中的条件判断表达式
- 逻辑运算符||和&&左边的操作数(作为条件判断表达式)
以上情况中,非布尔值会被隐式强制类型转化为布尔值,遵循前面介绍过得ToBoolean抽象规则
||和&&
准确来说,应该将它们称为"选择器运算符"
它们的返回值是两个操作数中的一个(且仅一个)
- ||和&&首先会对第一个操作数执行条件判断,如果其不是布尔值,则先进行ToBoolean强制类型转换,然后再进行条件判断
- 对||来说,如果条件判断结果为true则返回第一个操作数的值(不一定是布尔值),如果是false直接返回第二个操作数的值
- 对&&来说,如果条件判断为true就直接返回第二个操作数的值,为false直接返回第一个操作数的值
- 在if和for中其实会隐式将||和&&的返回结果隐式转换为布尔值从而进行条件判断
a || b
//相当于
a ? a : b
a && b
//相当于
a ? b : a
符号的强制类型转换
- ES6允许从符号到字符串的显示强制类型转换,然而隐式强制类型转换会产生错误
- 符号不能够被强制类型转换为数字(不管显隐),但可以强制类型转换为布尔值
宽松相等和严格相等
正确的解释是:“==允许在相等比较上进行强制类型转换,而===不允许”
抽象相等
- 如果两个值的类型相同的情况下
- (1)先注意几个常规的情况:
- NaN不等于NaN
- +0等于-0
- (2)两个对象指向同一个值是则视为相等,不发生强制类型转换
- 不符合以上情况,就根据同类型直接比较是否相等
- (1)先注意几个常规的情况:
- 如果两个值的类型不同的情况下
- 字符串和数字之间的相等比较
- 如果Type(x)是数字,Type(y)是字符串,返回x == ToNumber(y)的结果
- 反之,返回ToNumber(x) == y的结果,即以数字为基准类型
- 其他类型和布尔类型之间的相等比较
- 如果Type(x)是布尔类型,则返回ToNumber(x) == y的结果,若类型不一致
- 如果Type(y)是布尔值,则返回x == ToNumber(y)的结果,即也是以数字为基准类型
- 待布尔值转换为数字后,剩下的是数字和非布尔的类型的比较了,此时要进行二次判断,即考虑数字和字符串的比较,null和undefined和情况,以及对象与非对象之间的相等比较,接下讨论这两种情况
- null和undefined之间的比较
- 如果x为null,y为undefined,则结果为true
- 如果x为undefined,y为true,则结果为true
- 即在==中null和undefined相等,除此之外其他值都不存在这种情况,即null与null和undefined相等,除此之外其他都不相等,反之undefined也一样
- 对象和非对象之间的相等比较
- 如果Type(x)是字符串或数字,Type(y)是对象,则返回x == ToPrimitive(y)的结果
- 如果Type(x)是对象,Type(y)是字符串或数字,则返回ToPromitive(x) == y的结果,即先处理对象为优先,之后再根据返回的简单值进行二次判断,综合以上规则。
- 比较少见的情况
false == {}; //false "" == 0; //true "" == {}; //false 0 == {}; //false "" == [null]; //true
- 安全运用隐式强制类型转换
- 如果两边的值中有true或false,千万不要使用==
- 如果两边的值中有[]、""或者0,尽量不要使用==
- 字符串和数字之间的相等比较
抽象关系比较
- 比较双方首先调用ToPrimitive,如果结果出现非字符串,就根据ToNumber规则将双方强制类型转换为数字来进行比较
- 如果双方都是字符串,则按字母顺序来进行比较
以上内容来自《你不知道的JS中卷》的知识整理