类型转换
- JavaScript为基本数据类型提供了封装对象,它们被称为原生函数(String、Number、Boolean),并且为基本数据类型值提供了特有的方法和属性(toString()、length)。
- 基于基本类型的值,js引擎会自动对该值进行封装,来实现对这些属性和方法的访问。
- toPrimitive抽象操作(内部使用的操作)包括toString、valueOf、toNumber、toBoolean。
字符串
-
toString()
处理非字符串到字符串的转换,还有一些特殊的地方:- 数组的
toString()
经过了重新定义(你也可以),对所有的单元字符串化后再通过“,”连接起来; - json字符串化
JSON.stringify()
函数也涉及到toString的规则。JSON.stringify()
只对安全型的JSON值做转换。不安全型的值:undefined、function、symbol以及对象的循环引用,遇到这类值时会被忽略,遇到循环引用则会报错。 JSON.stringify()
第二个参数可以传入一个可选参数relpacer,可以是数组或者函数:- 数组必须是一个字符串数组,包含对象的属性名称,除了数组之外的属性以外,其他的值将会被忽略:
const obj = { a: 1, b: '2', c: 3 }; console.log(JSON.stringify(obj, ['a', 'c'])); // {"a":1,"c":3}
- 如果是函数,会对对象本身调用一次,然后对对象中的每个属性调用一次。
- 数组必须是一个字符串数组,包含对象的属性名称,除了数组之外的属性以外,其他的值将会被忽略:
- 第三个参数space可以用来指定缩进格式。
- 数组的
-
隐式类型转换:’’ + x(一方是字符串时会被当作字符串拼接);
数字
Number()
处理其他类型到数字的转换,如果无法换转回返回NaN(如function或者’111hhh’);- parseInt(只针对字符串)、parseFloat也能够(只针对浮点数);
- 隐式类型转换:+(x)(“+”的一方不是字符串时会被认为是+法运算);“-”也可以,但写法上要注意:
const n = '2' console.log(-n); // -2 console.log(+n); // 2 console.log(- -n); // 2 注意空格!
- 字位运算符 “~”,强制将类型转换为32位数字然后对每一个字位进行反转,类似于 ~(x+1)。这么说可能会让人一头雾水,看下面的例子:
const a = 'abcdefg' console.log(a.indexOf('de')); // 3 console.log(~a.indexOf('de')); // -4 x +1 反转 // 和indexOf可以将结果强制类型转换 // 如果indexOf 返回 -1 ~会将其转为假值0,其他情况一律位真值 if (~a.indexOf('de')) { // true console.log('找到你了'); // ~~ 类似 !! console.log(~~a.indexOf('de')); // 3 }
- ~~还可以用来做字位截除(只适用于32位数字):
const a = 3.333333 console.log(~~a); // 3
- ~~还可以用来做字位截除(只适用于32位数字):
布尔值
Boolean
显示转换;- 在if()、for第二个表达式、while,三目运算符语句、等也会对值进行布尔值转换;
- 隐式转换:! 或者 !!;
const b = ''; console.log(Boolean(b)); // false console.log(!b); // true console.log(!!b); // false
- 逻辑运算符 || 和 &&,应该称为选择器运算符,会首先对第一个值进行强制类型转换(如果不是布尔值),然后再执行条件判断:
- || 的规则是如果判断位true,返回第二个(或者为true)的那个值;
- && 的规则相反如果条件为true,返回第一个变量的值。
宽松相等和严格相等
- 误区:==检查值是否相等,===检查值和类型是否相等;
- 正确的解释是:==允许再相等比较重进行强制类型转换,而 === 不允许。
-
字符串和数字比较:
- 如果 x是数字,y是字符串,则返回 x == toNumber(y);
- 如果 x是字符串,y是数组,则返回 toNumber(x) == y;
const a = '7'; const b = 7; console.log(a == b); // true console.log(a === b); // false
-
其他类型和布尔值比较:
- 如果x是布尔值,则返沪 toNumber(x) == y;
- 如果y是布尔值,则返沪 x == toNumber(y);
const a = '7'; const b = true const c = false // 是不是很奇怪 console.log(a == b); // false console.log(a == b); // false
注意,变量a是一个真值没错,但变量b或者c被强制类型转换为1和0,那么 a == 1 || 0吗?
另外不要使用a == true此类的语法。 -
null和undefined比较
- 如果x为null,y为undefined,结果为true;
- 如果x为undefined,y为null,结果为true;
- 也就是说再==中undefined和null是一回事。
-
对象和非对象之间比较(布尔值会先被强制转换为数字):
- 如果x是数字或者字符串,y是对象则返回 x == toPrimitive(y)的结果;
- 如果x是对象,y是数字或者字符串则返回 toPrimitive(x) == y的结果;
const a = ['7'] ; const b = '7' console.log(a == b); // 抽象操作toString() ‘7’ true const b = '7' const a = new String('7'); console.log(a.valueOf()); // '7' console.log(a == b); // 在 == 时会“打开”封装对象,获取其原始值 true
-
总结
- 显示强制类型转换有助于提高代码可读性和维护性,隐式类型转换的优点是使代码更加简洁;
- 安全运用隐式强制类型转换:
- 如果两边中的值有true或者false,不要用 ==;
- 如果两边的值有[]、’’、0,尽量不要用 ==;
- == 和 ===用哪个取决于是否允许在比较时发生强制类型转换。
- 处理类型转换时要知其然还要知其所以然。