javascript中的类型转换已经是老生常谈的问题了,是基础中的基础,也是面试当中最爱问的问题,但一不注意还是会进坑。我也是在这里花了点时间想搞清楚js中类型转换的一些原理,做些笔记,只有明白了js在类型转换中做了什么,才能看清本质。
javascript中的数据类型
javascript中的类型可分为原始数据类型(number,string,boolean,null,undefined)和对象引用类型(object,array,function),这里先不考虑ES6中的symbol类型。
下面强制转换的结果是什么?
console.log(Number({})); //NaN
console.log(Number(['2'])); //2
console.log(Number([])); //0
console.log(Number(true)); //1
console.log(Number(function(){return 0;})); //NaN
console.log(String([1,2])); //1,2
console.log(String({a:12,b:true})); //[object Object]
console.log(String(function(){return 0;})); //function(){return 0;}
可以试着总结一下规律
-
转数值类型
- 对象、函数转成NaN (Not a Number)
- 空数组转为0,数组里只有一个数据并且这个数据能转成数字,则转成对应的数字,其它都转成NaN
- true转换为1,false转换为0
-
转字符串类型
- 数组的结果为把所有中括号去掉,外面加个引号(真正的原理是调用了数组的join(',')方法)
- 对象的结果为'[object Object]'(日期除外)
- 函数的结果为在函数整体外面加个引号
-
对象转布尔值都为true
浅析转换的原理
在学习javascript中说一切都是对象,这么说是有根据的,不论是原始值类型还是引用类型,每一种都对应一个包装对象(null和undefined这两种特殊值除外)
- number —— Number
- string —— String
- boolean —— Boolean
- object —— Object
- function —— Function
注意右侧的包装类型首字母为大写。在定义一个类型的变量时,其实本质就是定义了某一种类型的对象,既然是对象,就可以调用对象中的方法。
javascript的对象都有 valueOf 和 toString 这两个方法,对象转换的本质就是内部调用这两个函数以达到转换类型的目的。
试试看valueOf和toString都输出什么
var num=12;
var str='Tom';
var bool=true;
var arr=[12,45,['red','green']];
var fn=function(){return 1};
var obj={a:12};
console.log(num.toString(),num.valueOf()); //12 12
console.log(str.toString(),str.valueOf()); //Tom Tom
console.log(bool.toString(),bool.valueOf());//true true
console.log(arr.toString(),arr.valueOf()); //12,45,red,green (3) [12, 45, Array(2)]
console.log(fn.toString(),fn.valueOf()); //function (){return 1} ƒ (){return 1}
console.log(obj.toString(),obj.valueOf()); //[object Object] {a: 12}
总结一下规律
- 数字
- valueOf 返回本身
- toString 转成字符串
- 字符串
- valueOf 返回本身
- toString 返回本身
- 布尔值
- valueOf 返回本身
- toString 转成字符串
- 数组
- valueOf 返回本身
- toString 转成字符串,调用join方法
- 函数
- valueOf 返回本身
- toString 转成字符串,外面加引号
- 对象
- valueOf 返回本身
- toString [object Object]
上面说在进行类型转换时会由javascript调用valueOf 和 toString,并不是简单的猜测,为了证实这一点,我们可以用代码检验一下。
var arr=[1,2,3];
arr.valueOf=function(){
alert('没有骗你,真的调用了valueOf');
return [1,2,3];
};
arr.toString=function(){
alert('没有骗你,真的调用了toString');
return '1,2,3';
};
console.log(Number(arr));
console.log(String(arr));
以上代码定义了一个数组类型arr,并由我们自己重写了arr上的valueOf和toString的方法,当然,这仅仅是做个小实验,把这段代码放在chrome中运行,会发现确实弹出了提示。
看来javascript在类型转换的一瞬间,确实调用了valueOf或是toString。
转换为数值类型
当一个对象最终目标是要转换为数值类型时,javascript会自动调用valueOf方法,若结果就是原始类型的值,则始用Number()转换一下,并返回结果。
可以用代码模拟实验一下:
var arr=[1];
arr.valueOf=function(){
alert('调用了valueOf');
return Number([1]); //返回1
};
arr.toString=function(){
alert('调用了toString');
return '1';
};
以上代码运行后弹出了“调用了valueOf”并返回结果1(注意,toString方法没有执行),证实了猜测。一开始总结规律时,数组里只有一个数据并且这个数据能转成数字,则转成对应的数字,上面代码只有一个元素的数组arr=[1],因此能够正确转为数值1。
如果valueOf返回的结果仍然是个对象,那怎么办呢?这时,javascript会继续调用对象上的toString方法,再看看能否转为原始值,如果确实可以,就使用Number()转换一下并返回结果。
再做个小实验:
var arr=[1];
arr.valueOf=function(){
alert('调用了valueOf');
return [1]; //这里返回不是原始值了,是个Array
};
arr.toString=function(){
alert('调用了toString');
return Number([1]); //返回1
};
console.log(Number(arr));
再次运行以上代码,会发现先调用了valueOf,由于valueOf返回的结果是个对象(Array),并不是原始值,所以javascript又调用了toString再尝试一次,toString的结果是原始值,则返回转换后的正确结果1。
这时可能有个更极端的想法,如果valueOf和toString都没有返回原始值,那该怎么办呢?那么javascript也无能为力了,只有报错,输出错误消息。
眼见为实,再试一下:
var arr=[1];
arr.valueOf=function(){
alert('调用了valueOf');
return [1]; //这里返回不是原始值了,是个Array
};
arr.toString=function(){
alert('调用了toString');
return [1]; //还是返回Array,我看你怎么办
};
console.log(Number(arr));
再次运行以上代码,可以看到在chrome的控制台输出一行红色的错误:Uncaught TypeError: Cannot convert object to primitive value
大概意思是:“我不能把对象转换为原始值”。
其实,这种情况极为少见,在这里只不过是我们自己“制造”了个错误,来验证javascript内部的转换逻辑。说到这,就把javascript内部类型转换的基本思路说通了。
转换为字符串类型
转换字符串类型和转换数值类似,区别只是先调用toString,再调用valueOf,仅此而已。
原理最后总结
对象转数值
- 调用对象的valueOf方法。如果返回原始类型的值,再使用Number函数,不再进行后续步骤
- 如果valueOf方法返回的还是对象,则调用toString方法
- 如果toString方法返回原始类型的值,则对该值使用Number方法,不再进行后续步骤
- 如果toString方法后返回的是还是对象,就报错(一般不会出现)
对象转字符串
- 调用对象的toString方法。如果返回原始类型的值,再使用String函数,不再进行后续步骤
- 如果toString方法返回的还是对象,再调用对象的valueOf方法
- 如果valueOf方法返回原始类型的值,则对该值使用String函数,不再进行以下步骤
- 如果valueOf方法返回的是还是对象,就报错(一般不会出现)
搞清楚了原理以做出笔记,和大家共同学习进步。
网友评论