-
前言
javascript是一门残疾的垃圾语言,有很多莫名其妙的隐式转换,产生一些正常人难以理解的结果。
参考:https://www.cnblogs.com/chenmeng0818/p/5954215.html
-
基本类型
基本类型 number、string、boolean、null、undefined、object、symbol
-
运算符的隐式转换
*, /,和%等算术运算符都会把操作数转换成数字的,但是“+”号很特殊,有些情况下,它是算术加号,有些情况下,是字符串连接符号,具体的要看它的操作数
- 例子1:
const log = console.log;
//基本类型 number、string、boolean、null、undefined、object、symbol
log("'3' * 5 = ", ('3' * 5));//'3' * 5 = 15
log("3+ true = ", (3 + true));//3+ true = 4
log("3 + false = ", (3 + false));//3 + false = 3
log("8 + null = ", (8 + null));//8 + null = 8
log("8 + undefined = ", (8 + undefined));//8 + undefined = NaN
log("1+2+'3' = ", (1 + 2 + '3'));//1+2+'3' = 33
log("'3' + 2 = ", ('3' + 2));//'3' + 2 = 32 字符串与数字相加,把数字转成字符串
log("'3' + true = ", ('3' + true));//'3' + true = 3true
log("'7' + null = ", ('7' + null));//'7' + null = 7null
log("'7' + undefined = ", ('7' + undefined));//'7' + undefined = 7undefined
log("'7'*undefined = ",('7'*undefined));
log("'7'*null = ",('7'*null));
log("'7'*true = ",('7'*true));
log("'7'*false = ",('7'*false));
log("'7'*2 = ",('7'*2));
log("6*undefined = ",(6*undefined));
log("6*null = ",(6*null));
log("6*true = ",(6*true));
log("6*false = ",(6*false));
log("6*2 = ",(6*2));
log("end")
结果:
'3' * 5 = 15
3+ true = 4
3 + false = 3
8 + null = 8
8 + undefined = NaN
1+2+'3' = 33
'3' + 2 = 32
'3' + true = 3true
'7' + null = 7null
'7' + undefined = 7undefined
'7'*undefined = NaN
'7'*null = 0
'7'*true = 7
'7'*false = 0
'7'*2 = 14
6*undefined = NaN
6*null = 0
6*true = 6
6*false = 0
6*2 = 12
end
-
几个undefined、null、[]的隐式转换
代码:
const log = console.log;
let a = 7.38923;
log("null == undefined : ", (null == undefined));
log("null == 0 : ", (null == 0));
log("0 == undefined : ", (0 == undefined));
log("'' == null : ", ('' == null));
log("'' == undefined : ", ('' == undefined));
log("[] == null : ", ([] == null));
log("[] == undefined : ", ([] == undefined));
log("[] == '' : ", ([] == ''));
log("Number('null') : ", Number('null'));
log("Number('undefined') : ", Number('undefined'));
log("Number(NaN) : ", Number(NaN));
log("Number([]) : ", Number([]));
log("Number('') : ", Number(''));
log("Number('0') : ", Number('0'));
log("Number(' ') : ", Number(' '));
log("NaN == NaN : ", (NaN == NaN))
log("Number.NaN == NaN : ", (Number.NaN == NaN))
log("typeof(null) : ", typeof (null))
log("typeof(undefined) : ", typeof (undefined))
log("typeof(NaN) : ", typeof (NaN))
log("end")
结果:
PS E:\study\js\two\src> node .\testjs.js
null == undefined : true
null == 0 : false
0 == undefined : false
'' == null : false
'' == undefined : false
[] == null : false
[] == undefined : false
[] == '' : true
Number('null') : NaN
Number('undefined') : NaN
Number(NaN) : NaN
Number([]) : 0
Number('') : 0
Number('0') : 0
Number(' ') : 0
NaN == NaN : false
Number.NaN == NaN : false
typeof(null) : object
typeof(undefined) : undefined
typeof(NaN) : number
end
-
对象的隐式转换
所有对象继承了Object.prototype的两个转换方法:
第一个是toString(),它的作用是返回一个反映这个对象的字符串;
第二个是valueOf(),它的作用是返回它相应的原始值;
但一些内置对象重写了这两个方法,下面展示了一些内置对象调用这两个方法的返回情况。
类型 | toString | valueOf |
Object | 返回"[object ObjectName]",其中 ObjectName 是对象类型的名称。 | 对象本身。这是默认情况。 |
String | 返回 String 对象的值 | 字符串值。 |
Number | 返回数值的字符串表示。还可返回以指定进制表示的字符串,请参考Number.toString()。 | 数字值。 |
Boolean | 如果布尔值是true,则返回"true"。否则返回"false"。 | Boolean 值。 |
Array | 将 Array 的每个元素转换为字符串,并将它们依次连接起来,两个元素之间用英文逗号作为分隔符进行拼接。 | 数组本身 |
Date | 返回日期的文本表示。 | 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC |
Function | 返回如下格式的字符串,其中 functionname 是一个函数的名称,此函数的 toString 方法被调用: "function functionname() { [native code] }" | 函数本身。 |
那么toString和valueOf分别什么时候调用呢?
原始类型(primitive value)包括以下几类:null,undefined,string,number,boolean。
如果valueOf
或toString
返回非primitive value,它们将被忽略。如果都不存在或都不返回primitive value,则抛出TypeError: Cannot convert object to primitive value。
例子2:
const log = console.log;
function Dog(name, age) {
this.name = name;
this.age = age;
}
Dog.prototype.toString = function () {
return "dog tostr " + this.name + " " + this.age;
}
let dog1 = new Dog('aname', 8);
let dog2 = new Dog('bname', 7);
log("'a'+ dog1 = ", ('a' + dog1));
log("'a'+dog2 = ", ('a' + dog2));
log("dog1.toString() = ", dog1.toString());
log("dog2.toString() = ", dog2.toString());
log('dog1 = ', dog1, ", valueOf = ", dog1.valueOf());
log('dog2 = ', dog2, ", valueOf = ", dog2.valueOf());
log("'a1.toString() = ", 'a1'.toString(), ", 'a1'.valueOf = ", 'a1'.valueOf());
let num = 32;
log("typeof(num.toString()) = ", typeof (num.toString()), ", typeof(num.valueOf()) = ", typeof (num.valueOf()));
let bl = true;
log("typeof(bl.toString()) = ", typeof (bl.toString()), ", typeof(bl.valueOf()) = ", typeof (bl.valueOf()));
log("function Dog = ", Dog, ", typeof(Dog) = ", typeof (Dog));
log("function Dog.toString() = ", Dog.toString(), ", typeof(Dog.toString()) = ", typeof (Dog.toString()));
log("function Dog.valueOf() = ", Dog.valueOf(), ", typeof(Dog.valueOf() = ", Dog.valueOf());
log("end")
结果:
'a'+ dog1 = adog tostr aname 8
'a'+dog2 = adog tostr bname 7
dog2.toString() = dog tostr bname 7
dog1 = Dog { name: 'aname', age: 8 } , valueOf = Dog { name: 'aname', age: 8 }
dog2 = Dog { name: 'bname', age: 7 } , valueOf = Dog { name: 'bname', age: 7 }
'a1.toString() = a1 , 'a1'.valueOf = a1
typeof(num.toString()) = string , typeof(num.valueOf()) = number
function Dog = [Function: Dog] , typeof(Dog) = function
function Dog.toString() = function Dog(name, age) {
this.name = name;
this.age = age;
} , typeof(Dog.toString()) = string
function Dog.valueOf() = [Function: Dog] , typeof(Dog.valueOf() = [Function: Dog]
end
PS E:\study\js\two\src> node .\testjs.js
'a'+ dog1 = adog tostr aname 8
'a'+dog2 = adog tostr bname 7
dog1.toString() = dog tostr aname 8
dog2.toString() = dog tostr bname 7
dog1 = Dog { name: 'aname', age: 8 } , valueOf = Dog { name: 'aname', age: 8 }
dog2 = Dog { name: 'bname', age: 7 } , valueOf = Dog { name: 'bname', age: 7 }
'a1.toString() = a1 , 'a1'.valueOf = a1
typeof(num.toString()) = string , typeof(num.valueOf()) = number
typeof(bl.toString()) = string , typeof(bl.valueOf()) = boolean
function Dog = [Function: Dog] , typeof(Dog) = function
function Dog.toString() = function Dog(name, age) {
this.name = name;
this.age = age;
} , typeof(Dog.toString()) = string
function Dog.valueOf() = [Function: Dog] , typeof(Dog.valueOf() = [Function: Dog]
end
-
其它隐式转换
-
对象和布尔值比较
对象和布尔值进行比较时,对象先转换为字符串,然后再转换为数字,布尔值直接转换为数字
例子:
const log = console.log;
log("[] == false ", ([] == false), ", [] === false ", ([] === false));
log("'' == false ", ('' == false), ", '' === false ", ([] === false));
log("end")
结果:
[] == false true , [] === false false
'' == false true , '' === false false
end
- 对象和字符串比较
对象和字符串进行比较时,对象转换为字符串,然后两者进行比较。
[1,2,3] == '1,2,3' // true [1,2,3]转化为'1,2,3',然后和'1,2,3', so结果为true;
- 对象和数字比较
对象和数字进行比较时,对象先转换为字符串,然后转换为数字,再和数字进行比较。
[1] == 1; // true `对象先转换为字符串再转换为数字,二者再比较 [1] => '1' => 1 所以结果为true
-
字符串和数字比较
字符串和数字进行比较时,字符串转换成数字,二者再比较。
'1' == 1 // true
- 字符串和布尔值比较
字符串和布尔值进行比较时,二者全部转换成数值再比较。
'1' == true; // true
- 布尔值和数字比较
布尔值和数字进行比较时,布尔转换为数字,二者比较。
true == 1 // true
许多刚接触js的童鞋看到这么多的转换规则就懵圈了,其实规律很简单,大家可以记下边这个图
如图,任意两种类型比较时,如果不是同一个类型比较的话,则按如图方式进行相应类型转换,如对象和布尔比较的话,对象 => 字符串 => 数值 布尔值 => 数值。
- 另外,我们来看下一些需要"特别照顾"的。
来看一个有趣的题
例子:
const log = console.log;
log("[] == false ",([] == false));
log("![] == false ",(![] == false));
log("end")
结果:
[] == false true
![] == false true
end
这两个的结果都是true,第一个是,对象 => 字符串 => 数值0 false转换为数字0,这个是true应该没问题,
第二个前边多了个!,则直接转换为布尔值再取反,转换为布尔值时,空字符串(''),NaN,0,null,undefined这几个外返回的都是true, 所以! []这个[] => true 取反为false,所以![] == false为true。
还有一些需要记住的,像:
undefined == null //true undefined和null 比较返回true,二者和其他值比较返回false
Number(null) //0