Prakticky každý programovací jazyk, se potýká s typovými konverzemi. V Javascriptu se s typovou konverzí vypořádáváme s pomocí abstraktních operací.
Máme možnost v objektech definovat metody, jako jsou toPrimitive
, toString
, toNumber
, toBoolean
, díky kterým implementujeme vlastní způsob konverze.
Existují i další abstraktní operace které se používají, ale popíšeme si jen ty na které pravděpodobně běžně narazíte. Pokud vás zajímají i jiné, přečtěte si specifikaci.
K automatickému volání abstraktních operací, dochází nejčastěji v situacích
-
kdy kontrolujeme splnění podmínky v
if
nebo v ternárním operátoru, kde očekáváme boolean s odpovědí pravda/nepravda. -
když používáme operátor dvojité rovná se.
-
pokud se objekt použije jako operand v operaci konkatenace
+
. -
pokud jeden z operandů není číselný a pracujeme s aritmetickými operacemi nebo s operacemi srovnání.
-
objekt se použije jako argument pro funkci
Number()
neboString()
. -
v template literals používáme proměnné, které se převádí na text
ToPromitive
První abstraktní operace, kterou si představíme se nazývá ToPrimitive
.
Spousta operátorů JS funguje pouze s primitivními datovými typy a v tomto případu pokud se v operaci ocitne objektový typ (např. objekt, pole, funkce),
musíme ho neprve přeměnit na primitivní datový typ. V tomto je JS specifičtější, protože v mnoha jiných technologiích pokud se o tohle pokusíme dostaneme spíše chybu.
Tato abstraktní operace se na téhle konverzi bude podílet.
Pro objekty se metoda ToPrimitive()
chová tak, že nejprve hledá existenci metody valueOf()
a pokud tuto metodu nenajde, použije metodu toString()
.
Pokud ani tato metoda není k dispozici, vyhodí se chyba TypeError
.
Pokud návratový výsledek z ToPrimitive
není primitivní typ, ale jde o jiný objekt než jsme dříve vložili, pak se s tímto dalším objektem vyvolá toPrimitive
znovu a bude se vyvolávat tak dlouho, dokud nedostaneme něco, co je skutečným primitivem, nebo nedostaneme chybu.
Výsledek ToPrimitive
tedy a skončí buď voláním valueOf()
, toString()
nebo chybou.
Nápověda typu
Jeden z volitelných argumentů metody je "hint", jehož smyslem je naznačit, pokud máte něco, co není primitivní, jaký typ byste preferovali dostat.
Implicitní hodnota nápovědy je "default".
Pokud však provádíte číselnou operaci, která vyvolá ToPrimitive
, jako nápovědu pošle "number".
V jiném případě při práci s řetězci, dostanete nápovědu "string".
Pokud v nápovědě příjde např. hodnota "number", pak se nejprve pokusím vyvolat hodnotu valueOf()
zda je primitivní.
Pokud vrátí primitivum, pak jsme hotoví. Pokud mi to primitivum nedá nebo neexistuje, pak zkusí zavolat toString()
.
Další argument je "preferredType" (pouze v ECMAScript 6), který určuje, zda se má použít metoda valueOf nebo toString.
ToString
Téměř každá hodnota, která v JS existuje má alespoň nějaký druh reprezentace ve formě řetězce.
Konverze primitivních typů na string
Metoda toString
^tc39-tostring je dostupná pro všechny primitivní typy (např. number, boolean), u kterých vrátí řetězec, který představuje jejich hodnotu.
Čísla je možné velice jednoduše převést na řetězce, ale u opačné konverze je situace složitější.
Z tohoto důvodu jsou v jazyce k dispozici funkce parseInt()
a parseFloat()
.
U nulové nebo nedefinovaná hodnoty, vrátí se řetězec "null" nebo "undefined", jak byste nejspíše čekali.
Konverze ostatních typů na string
Pokud je toString
volána nad objektem, vrátí se řetězec, který představuje tento objekt.
Pole mají vlastní toString
logiku, která serializuje položky pole.
Nicméně může se zdát zvláštní, že se vynechávají závorky.
Takže pokud serializujete prázdné pole, dostanete prázdný řetězec.
[].toString(); // ""
[1,2,3].toString(); // "1,2,3"
[null, undefined].toString(); ; // ","
[[[],[],[]], []].toString(); // ",,,"
[,,,,].toString();// ",,,"
V případě objektů jako je Date, vrací metoda reprezentaci data a času.
V vlastních objektů, které nemají svou metodu toString
, tak se ve výchozím stavu volá Object.prototype.toString
, který nám vrátí reprezentaci typu objektu (string tag).
Můžete však prototype přepsat a naimplementovat logiku, ve které se objekt stringifikuje do JSONu apod.
Uvědomte si, že metoda toString()
je automaticky volána například pokud se snažíte spojit řetězec s jinou hodnotou pomocí operátoru "+", nebo při výpisu na konzoli apod.
ToNumber
Metoda toNumber()
slouží k převodu hodnoty na číslo.
JS se pokouší o konverzi, aby získal číselnou hodnotu, která je použitelná pro výpočet.
Konverze primitivních typů na number
Je dostupná pro všechny primitivní typy (např. string, boolean). Tato metoda se obvykle volá, když se pokoušíte použít algebraitské oprátory na objektu s číslem.
U konverze řetězce na číslo nás může překvapit
"" // 0
"0" // 0
"0xaf" // 175
U null dostáváme číselnou hodnotu 0 a u "undefined" zase NaN
.
V případě, že je hodnota, na které je metoda volána, jiný objekt nebo primitivní typ, který nelze konvertovat na číslo, metoda vrací NaN.
Konverze ostatních typů na number
Pokud je metoda volána s objektem, vrátí se hodnota, která reprezentuje tento objekt jako číslo.
Například volání new Date().toNumber()
vrátí timestamp reprezentující datum a čas.
V případě, že je argumentem funkce Number
objekt, pak se volá metoda toPrimitive
s nápovědou number.
U objektů a polí, pokud nejsou implementovány vlastní abstraktní operátory se volá valueOf
.
Ve většině případů bude metoda valueOf
vracet jen sama sebe. Což bude mít za následek, že se valueOf
ignoruje a zavolá se toString
.
To vede k tomu, že v různých operacích, kde jste očekávali primitivum, ale chtěli jste primitivní číslo, dostanete primitivní řetězec.
A pak nastoupí další koerce. Takže nakonec skončíme s toString
a na to, co toString vrátí, což může být standardní řetězec objektu z Object.prototype.toString
.
Což rozhodně není reprezentace čísla, takže dostaneme nakonec NaN.
To je vlastně rozumné. Je to hloupé, ale je to rozumné.
Pokud přepíšete valueOf
pro nějaký objekt, můžete vrátit, co chcete.
ToBoolean
Logika, kterou JS používá k převodu hodnot na hodnoty typu boolean je poměrně jednoduchá.
Specifikace definuje pár hodnot, které jsou vyhodnoceny jako false.
Tedy všechno co je undefined
, null
, false
, 0
, NaN
, "" (prázdný řetězec) je konvertováno na false.
Jinak ostatní hodnoty jsou konvertovány na true.
ValueOf
Existují dvě metody, které mohou být k dispozici na jakémkoli ne-primitivu, těmi jsou valueOf()
a toString()
.
Pokud je metoda volána na objektu, který má implementovanou i metodu toString(), JavaScript nejdříve volá metodu valueOf() a pokud vrátí hodnotu jinou než objekt, použije ji. Pokud vrátí objekt, volá na něm metodu toString().