深度剖析之由浅入深揭秘JavaScript类型转换(最全总结篇)
值类型转换
- • 将值从一种类型转换为另一种类型通常称为类型转换,分为
隐式强制类型转换
和显示强制类型转换
。两者的区别在于是否可直观看出。 - • 如下代码:
var a = 42; var b = a + ""; // 隐式强制类型转换 var c = String( a ); // 显式强制类型转换 b; // 42 c; // 42
- • 上述代码中,对于 b 而言是隐式转换,而对于 c 而言是显示转换。
抽象值操作
- • 在值类型转换前我们先来看看字符串、数字、布尔值之前的基本转换规则。
toString
- • 该操作,
负责处理非字符串到字符串的强制类型转换。
- • 例如:null -> "null",undefined -> "undefined", true -> "true"
- •
对于普通对象来说,除非自定义,否则都会调用其内部的 toString() 方法。
- • Array
- •
数组的toString() 方法经过了重定义,会将所有数组元素用
,连接起来。
var a = [1,2,3]; a.toString(); // 1,2,3
- • JSON
- • 工具函数 JSON.stringify() 在将 JSON 对象序列化为字符串时也用到了 toString
- • 对于大多数简单值来说,JSON 字符串与 toString() 的结果基本相同。但对于某一些值来说不同,例如:undefined, function, symbol, 循环引用(对象之间的相互引用,行程一个无限循环),JSON.stringify() 就无法处理它。
- • 如下代码:
JSON.stringify(undefined); // undefined JSON.stringify(function () {}); // undefined JSON.stringify([1, undefined, function () {}, 4]); // "[1,null,null,4]" JSON.stringify({ a: 2, b: function () {} }); // "{"a":2}" JSON.stringify([undefined, Object, Symbol("")]); // '[null,null,null]'
- • 对于包含循环引用的对象执行 JSON.stringify() 会出错。但我们可以通过
toJSON()
方法进行重写。 - • 如下代码:
// eg1: var o = { }; var a = { b: 42, c: o, d: function(){} }; // 在a中创建一个循环引用 o.e = a; // 循环引用在这里会产生错误 // JSON.stringify( a ); // TypeError: Converting circular structure to JSON // 自定义的JSON序列化 a.toJSON = function() { // 序列化仅包含b return { b: this.b }; }; JSON.stringify( a ); // "{"b":42}" // eg2: var a = { val: [1,2,3], // 可能是我们想要的结果! toJSON: function(){ return this.val.slice( 1 ); } }; JSON.stringify( a ); // "[2,3]"
- • 还有关于 JSON.stringify() 的不太为人知的功能:
- • 可向 JSON.stringify() 中传递第二个参数 replacer, 可以是
数组或函数
。 - •
如果 replacer 为数组, 那它必须为字符串数组,数组中包含了要序列化要处理的对象 key, 除此之外的属性则会被忽略
。 - •
如果 replacer 为函数,那它会对对象本身调用一次,然后对对象中的每个属性各调用一次,可传递两个参数,键和值。
- • 如下代码:
var a = { b: 42, c: "42", d: [1,2,3] }; // replacer 为数组 JSON.stringify( a, ["b","c"] ); // "{"b":42,"c":"42"}" // replacer 为函数 JSON.stringify( a, function(k,v){ if (k !== "c") return v; } ); // "{"b":42,"d":[1,2,3]}"
- •
还有一个可选参数 space,用于指定缩进格式。
var a = { b: 42, c: "42", d: [1,2,3] }; JSON.stringify( a, null, 3 ); // "{ // "b": 42, // "c": "42", // "d": [ // 1, // 2, // 3 // ] // }"
- • 总结:
- •
对于字符串,数字,布尔值和 null,结果与 toString() 基本相同。
- •
如果在 JSON.stringify() 的对象中重定义了 toJSON() 方法,那该方法会在字符序列化前调用。
toNumber
- • 其中 true 转换为 1,false 转换为 0。undefined 转换为 NaN,null 转换为 0。
- • 将值转换时会遵循以下规则:
- •
在使用 Number() 或 toNumber() 方法将一个字符串转换为数字时,如果字符串中出现非数字字符,则会返回 NaN。
let obj = { // 首先调用 [Symbol.toPrimitive]() { return 200; }, // 中间调用 valueOf() { return 300; }, // 最后调用 toString() { return 'Hello'; } } console.log(obj + 200); // 400
toBoolean
- • 以下这些是假值:
• undefined • null • false • +0、-0 和 NaN • "" // 假值的布尔强制类型转换结果为 false。
- • 我们可以这么理解除了以上假值列表意外的值都是真值。
// eg1: var a = new Boolean(false); var b = new Number(0); var c = new String(""); console.log(!!(a && b && c)); // true // eg2: var a = 'false'; var b = '0'; var c = "''"; console.log(!!(a && b && c)); // true
toPromitive
- • 转换规则:
- • 如果检查该值是否有 valueOf 方法,看是否会返回原始值,如果返回值是原始值,则直接使用。否则,就使用 toString 方法,如果 toString 方法返回的是原始值,则直接使用,否则抛出 TypeError 错误。
"0" == false; // true false == 0; // true false == ""; // true false == []; // true "" == 0; // true "" == []; // true 0 == []; // true
显示强制类型转换
- •
~(非) 运算符
- • 对于非运算符的理解:我们可理解为
~ 会返回 2 的补码
。
- • 如下:
// ~x 大致等于 -(x + 1)。 ~42; // -(42 + 1) ==> -43
- •
在 -(x + 1) 中唯一能够得到 0 的 x 值是 -1。也就是如果 x 为 -1 时,~ 与其他一些数字值会返回 false 值,否则返回 true 值。
// before var a = "Hello World"; if (a.indexOf( "lo" ) >= 0) { // true // 找到匹配! } if (a.indexOf( "lo" ) != -1) { // true // 找到匹配! } if (a.indexOf( "ol" ) < 0) { // true // 没有找到匹配! } if (a.indexOf( "ol" ) == -1) { // true // 没有找到匹配! } // after var a = "Hello World"; ~a.indexOf( "lo" ); // -4 <-- 真值! if (~a.indexOf( "lo" )) { // true // 找到匹配! } ~a.indexOf( "ol" ); // 0 <-- 假值! !~a.indexOf( "ol" ); // true if (!~a.indexOf( "ol" )) { // true // 没有找到匹配! }
- • 显示转换为布尔值
// before var a = "0"; var b = []; var c = {}; var d = ""; var e = 0; var f = null; var g; Boolean( a ); // true Boolean( b ); // true Boolean( c ); // true Boolean( d ); // false Boolean( e ); // false Boolean( f ); // false Boolean( g ); // false
// after 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
- • 在if() 判断中,如果没有使用 Boolean() 和 !!, 就会自动隐式进行 toBoolean 转换。