对于普通对象来讲,除非自行定义toString方法,不然就会调用Object.prototype.toString()方法,若是对象有本身的toString方法,字符串化就会调用该方法并使用其返回值。数组
let a = { valueOf:function(){ return "42"; } }; let b = { toString:function(){ return "42"; } }; let c = [4,2]; c.toString = function(){ return this.join(""); //"42" }; Number(a); //42 Number(b); //42 Number(c); //42 Number(''); //0 Number([]); //0 Number(["abc"];//NaN
JavaScript中的值能够分为能被强制转换为false的值和能被强制转换为true的值两类。
假值:安全
真值:除了以上列表的均可以理解为是真值,全部对象都是真值函数
let a1 = new Boolean( false ); let b1 = new Number( 0 ); let c1 = new String( "" ); let d1 = Boolean(a1 && b1 && c1); //true let a2 = []; let b2 = {}; let c2 = function(){}; let d2 = Boolean(a2 && b2 && c2); //true
字符串和数字之间的转换是经过 String(..) 和 Number(..) 这两个内建函数。
除了 String(..) 和 Number(..) 之外,还有其余方法能够实现字符串和数字之间的显式 转换:this
let a = 42; let b = a.toString(); let c = "3.14"; let d = +c; b; // "42" d; // 3.14
a.toString() 是显式的,不过其中涉及隐式转换。由于 toString() 对 42 这样的基本类型值不适用,因此 JavaScript 引擎会自动为 42 建立一个封装对象,而后对该对象调用 toString()。这里显式转换中含有隐式转换。prototype
let a = "0"; let b = []; let c = {}; let d = ""; let e = 0; let f = null; let g; Boolean( a ); // true Boolean( b ); // true Boolean( c ); // true Boolean( d ); // false Boolean( e ); // false Boolean( f ); // false Boolean( g ); // false
虽然 Boolean(..) 是显式的,但并不经常使用。显式强制类型转换为布尔值最经常使用的方法是 !!设计
let a = "0"; let b = []; let c = {}; let d = ""; let e = 0; let f = null; let g; !!a; // true !!b; // true !!c; // true !!d; // false !!e; // false !!f; // false !!g; // false
即能用于数字加法,也能用于字符串拼接
若是 + 的其中一个操做数是字符串(或者经过对其调用 ToPrimitive 抽象操做获得字符串), 则执行字符串拼接;不然执行数字加法。由于数组的 valueOf() 操做没法获得简单基本类型值,因而它转而调用 toString()。所以下例中的两个数组变成了 "1,2" 和 "3,4"。+ 将它们拼接后返回 "1,23,4"。code
let a = "42"; let b = "0"; a + b; // "420" let c = 42; let d = 0; c + d; // 42 let x = [1,2]; let y = [3,4]; x + y; // "1,23,4"
let a = 42; let b = a + ""; b; // "42"
根据 ToPrimitive抽象操做规则,a + ""会对a调用valueOf()方法,而后经过ToString抽象 操做将返回值转换为字符串。而 String(a) 则是直接调用 ToString()。它们最后返回的都是字符串,但若是 a 是对象而非数字结果可能会不同对象
let a = { valueOf: function() { return 42; }, toString: function() { return 4; } }; a + ""; // "42" String( a ); // "4"
-是数字减法运算符,所以a - 0会将a强制类型转换为数字。也可使用a * 1和a /1,由于这两个运算符也只适用于数字,只不过这样的用法不太常见ip
let a = [3]; let b = [1]; a - b; // 2
下面的状况会发生 布尔值隐式强制类型转换:
(1) if (..)语句中的条件判断表达式。字符串
(2) for ( .. ; .. ; .. )语句中的条件判断表达式(第二个)。
(3) while (..) 和 do..while(..) 循环中的条件判断表达式。
(4) ? :中的条件判断表达式。
(5) 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操做数(做为条件判断表达式)。
以上状况中,非布尔值会被隐式强制类型转换为布尔值,遵循前面介绍过的 ToBoolean 抽象操做规则。
== 容许在相等比较中进行强制类型转换,而 === 不容许。== 和 === 都会检查操做数的类型。区别在于操做数类型不一样时它们的处理方式不一样。
let a = 42; let b = "42"; a === b; // false a == b; // true
由于===没有强制类型转换,因此 a === b 为 false,42 和 "42" 不相等。而 a == b 是宽松相等,即若是两个值的类型不一样,则对其中之一或二者都进行强制类型转换。
转换规则以下:
(1) 若是 Type(x) 是数字,Type(y) 是字符串,则返回 x == ToNumber(y) 的结果。
(2) 若是 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x) == y 的结果。
let a = "42"; let b = true; a == b; // false
转换规则以下:
(1) 若是 Type(x) 是布尔类型,则返回 ToNumber(x) == y 的结果;
(2) 若是 Type(y) 是布尔类型,则返回 x == ToNumber(y) 的结果。
上例中Type(x)是布尔值,因此ToNumber(x)将true强制类型转换为1,变成1 == "42",两者的类型仍然不一样,"42" 根据规则被强制类型转换为 42,最后变成 1 == 42,结果为 false。
(1) 若是 x 为 null,y 为 undefined,则结果为 true。
(2) 若是 x 为 null,y 不是 undefined或者null,则结果为 false。
(3) 若是 x 为 undefined,y 为 null,则结果为 true。
(4)若是 x 为 undefined,y 不是 undefined或者null,则结果为 false。
let a = null; let b; a == b; // true a == null; // true b == null; // true a == false; // false b == false; // false a == ""; // false b == ""; // false a == 0; // false b == 0; // false
(1) 若是 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果;
(2) 若是 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。
let a = 42; var b = [ 42 ]; a == b; // true
[ 42 ] 首先调用 ToPromitive 抽象操做,返回 "42",变成 "42" == 42,而后 又变成 42 == 42,最后两者相等
"0" == null; // false "0" == undefined; // false "0" == false; // true -- "0" == NaN; // false "0" == 0; // true "0" == ""; // false false == null; // false false == undefined; // false false == NaN; // false false == 0; // true -- false == ""; // true -- false == []; // true -- false == {}; // false "" == null; // false "" == undefined; // false "" == NaN; // false "" == 0; // true -- "" == []; // true -- "" == {}; // false 0 == null; // false 0 == undefined; // false 0 == NaN; // false 0 == []; // true -- 0 == {}; // false
这时最好用 === 来避免不经意的强制类型转换。这两个原则可让咱们避开几乎全部强制 类型转换的坑。
如下状况返回true:
对于 ES6 以前的版本,Object.is(..) 有一个简单的 polyfill:
if (!Object.is) { Object.is = function(v1, v2) { // 判断是不是-0 if (v1 === 0 && v2 === 0) { return 1 / v1 === 1 / v2; } // 判断是不是NaN if (v1 !== v1) { return v2 !== v2; } // 其余状况 return v1 === v2; }; }