有些话先说一说:
Javascript偏向弱型别的语言,不需要像Java那样先指定变数的型态!
/* Java */String x = "10";String y = "20";x = 3; //且不能重新赋指定型态外的值int result = Integer.parseInt(x) - Integer.parseInt(y); //运算时也必须将型态明确剖析转换
在javascript里就不需要事先宣告变数的型态了,相对来说变得很弹性。
/* javascript */let x = '10';let y = '30';let result = y - x; // 20:可以直接做运算,型态会自动转换console.log(typeof result); // numberx = 10; //可以直接重新赋予任何型态的值
javascript里型态的转换很常发生,像是上述的let result = y - x;就发生了型态的转换,原本为字串的x与y转换成了数字(number型态),再看个例子:
let number = 100;number.toString();
toString是在物件上才有的方法(特性),此时(这里的number)就会自动使用Number实例来包裹100这个数字,因此才可以操作toString,同样也是进行了型态转换,自动转型。
上面讲了些基型值(如string,boolean,number etc...)的转换,那物件的转换呢?
let obj = { value : 10}let x = 10;console.log(x + obj);
基型值
指的是number
、boolean
、string
、null
、nudefined
这些javascript里的基本型态之值关于型态转换
型态的转换很常发生在运算的时候,在说物件的转换前,先从基型值的运算说起吧!
加号(+)
使用加号很简单,直接这样写即可
let num = 1 + 2;console.log(num); // 3
两个「数字」相加很单纯也很简单
但还有「特殊数字」,什么是特殊数字呢?Infinity
、-Infinity
、Nan
就是这里所说的特殊数字,来让他们相加看看
Infinity + Infinity //InfinityInfinity + -Infinity //NaN-Infinity + -Infinity //-Infinity
NaN
的话只要任何一个是NaN
的话,结果就是NaN
10 + NaN //NaNInfinity + NaN //NaN
那如果有一个是字串呢?
10 + 'String' //?10 + '10' //?
结果会是10String
在做加号+
运算的时候,有一边是字串的话会先做字串的串接,所以原是number型态
的10会转换成字串型态
,再做字串的串接动作,也就是会「自动转型」
number
、string
、boolean
会使用型态各自的Wrapper(包裹器)包裹后,使用toString()方法转成字串,而null
、undefined
这两个特殊小孩就没有各自的Wapper了,而是使用javascript的String()来转换成"null"、"undefined"字串。那如果是这样呢?可以自己思考看看或是试试看!
let x = 100;let y = 100;let result = '100 + 100:' + x + y; //?
物件型别的运算
物件型别的运算就不一样了,再物件上我们可以使用或是自定义toString
与valueOf
方法来转换,举个例子:
let obj = { valueOf: function() { return 100; }console.log(100 + obj); //200
当需要转换成数字时,先试valueOf()方法 object-to-number
物件型别的运算(加减乘除etc...),会先使用套用物件的valueOf
方法,如果回传的是基型值,javascript就会将基型值转换成数字(需要的话),并回传结果。物件上没有valueOf
方法的话就使用toString()方法,若该方法回传基型值,javascript将之转换并回传。若以上都达不到条件,就会抛出错误(TypeError)。需要证明是先套用valueOf()方法的话,加上toString试试看
let obj = { toString: function() { return 'one'; }, valueOf: function() { return 100; }console.log(100 + obj); //?
结果还是200,也是先套用了valueOf()方法
同样的上面obj,试试valueOf回传的不是基型值
valueOf: function() { return {}; }
结果为'100one',也证实了如果valueOf()回传的若不是基型值时会套用toString(),再依运算的需求来决定是否需要转换型态。
再来看看下面这个例子:
console.log({}.toString()); //[Objet Objet]console.log({}.valueOf()); //{}
会有这样的结果是因为物件在无定义toString()
与valueOf
的情况下,预设为toString()回传'[Object Object]'
,而valueOf()回传this
。
所以可以想想看下面的结果为何:
console.log(1 + {}); //?console.log(1 - {}); //?
物件型别做加减乘除时,都会先套用valueOf方法,也就是object-to-number
当需要将物件转成字串时,先试试toString() object-to-string
如果该物件有toString()方法,javascript会呼叫他,如果回传的是一个基型值(primitive),javascript会把那个值转换成字串(primitive-to-string
,也就是会用到wrapper)(不是字串的话),并回传结果。若没有toString()方法,或是回传的不是基型值时,就会改呼叫valueOf()方法(该方法存在的话),若回传的是基型值,就会把基型值转换成字串,并回传转换成字串后的值。若以上皆非,就会抛出TypeError错误