js中类型转换分为显示转换和隐式转换,下面我总结一下都有哪些情况会发生类型转换。
一.显示转换
1.通过调用 parseInt、parseFloat、new Number()等都会发生显示转换。在转换中的规则如下:
-
第一个字符是有效数字,就会将有效数字部分转换为数值;
console.log(parseInt('123abc')); // 123 -
第一个字符是非数字,就会转换为NaN;
console.log(parseInt('abc123')); // NaN
那么请看一下下面这道显式转换题:
var str = 'abc123',
num = parseFloat(str);
if (num === NaN) {
alert(NaN);
} else if (num === 123) {
alert(123);
} else if (typeof num === 'number') {
alert('number');
} else {
alert('str');
}
// 结果是: 'number'
最终输出
'number',原因是str第一个字符非数字,会转换成NaN,众所周知的NaN是不全等与NaN的。而typeof NaN是number,所以输出结果是'number'
二、隐式转换
众所周知,js中当遇到+ - * / > < ==等运算符的时候,会发生隐式转换。而+和其他运算符有一些不同。除了+,其他都会转换为数值型。
1.+操作符
-
对于
+,遇到字符串那么就会按照字符串拼接去计算,而不是简单的加运算。console.log('123'+ 456); // 123456 -
当非数字类型遇到
+的时候,也会发生隐式类型转换。// Boolean类型遇到数值,会转换成数值型。 true=1; false=0 console.log(true+1); // 2 console.log(false+1); // 1 console.log(false + false); // 0 console.log(true + true); // 2 // 当Boolean遇到字符串,会转换成字符串 console.log(true+'1'); // true1 -
当
+作为***一元操作符***的时候,其位于操作树的前面。如果操作数不是一个数值,会尝试将其转换成一个数值。这时候就发生隐式转换了。尽管一元负号也能转换非数值类型,但是一元正号是转换其他对象到数值的***最快方法***,也是***最推荐***的做法,因为它不会对数值执行任何多余操作。遇到不能转换的返回NaN。会将布尔类型、null、字符串转换为数值型。+3 // 3 +"3" // 3 +true // 1 +false // 0 +null // 0 +function(val){ return val;} //NaN
看如下一道面试题:
var a = 'abc' + 123 + 456;
alert(a); // abc123456
var b = '456' - '123';
alert(b); // 333
var c = 1,
d = '1';
var f = c > d ? (c < d ? c : d) : (c == d ? c : d);
alert(f); // 输出1
2.其他的隐式转换
-
当作为对象属性的key值时,所有类型都会被
toString()。// 数值类型作为属性名的时候,会被转换为字符串 var a = {}; b = 123; a[b] = 'hello'; console.log(Object.keys(a)) // ["123"] // 对象作为一个对象的属性名的时候,也会被转换为string。 var a={}, b={key:'123'}; a[b] = 'hello'; console.log(Object.keys(a)); // ["[object Object]"] // 而Symbol作为对象的属性名的时候,不会被转换. var a={}, b=Symbol('123'), c=Symbol('123'); a[b]='b'; a[c]='c'; console.log(a[b]); // 输出 'b'
所以看如下一道面试题:
// 题一
var a={}, b='123', c=123;
a[b]='b';
a[c]='c';
console.log(a[b]); // 都会转换为字符串123,所以 a[c]会覆盖a[b],输出 c
-----------------------------
// 题二
var a={}, b=Symbol('123'), c=Symbol('123');
a[b]='b';
a[c]='c';
console.log(a[b]); // Symbol是生成唯一值的。 所以b不等于c,输出 'b'
------------------------------
// 题三
var a={}, b={key:'123'}, c={key:'456'};
a[b]='b';
a[c]='c';
console.log(a[b]); // 对象类型作为属性名,都会被转换为string,所以a[b]会被a[c]覆盖掉。输出'c'
三、类型判断方法
类型判断的方法有typeof、instanceof、Object.prototype.toString.call(xxx) === '[object yyy]'。他们都有哪些优缺点呢?
1.typeof
它只能判断基本数据类型有:number、string、boolean、symbol、undefined。对于对象类型和null,统一都返回object.
console.log(typeof '123'); // string
console.log(typeof 123); // number
console.log(typeof false); // boolean
console.log(typeof Symbol(123)); // symbol
console.log(typeof undefined); // undefined
console.log(typeof null); // object
console.log(typeof new Date()); // object
2.instanceof
它用来检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。就是检测某个实例对象是不是该函数的实例
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);
console.log(auto instanceof Car); // true
console.log(auto instanceof Object); // true
3.Object.prototype.toString.call
最严谨的判断是通过Object.prototype.toString.call来判断类型。
console.log(Object.prototype.toString.call('123') === '[object String]'); // true
console.log(Object.prototype.toString.call(123) === '[object Number]'); // true
console.log(Object.prototype.toString.call(Symbol(123)) === '[object Symbol]'); // true
console.log(Object.prototype.toString.call(new Date()) === '[object Date]'); // true