Abstract Operations
Abstract Operations es básicamente lo que se encarga de hacer la conversión de tipos.
Estas operaciones abstractas, funcionan dentro del engine de JS y no pueden ser llamadas por el usuario.
Type Conversion (a.k.a coercion)
El lenguaje ECMAScript realiza implícitamente la conversión automática de tipos según sea necesario. Para aclarar la semántica de ciertas construcciones, es útil definir un conjunto de operaciones abstractas de conversión. Las operaciones abstractas de conversión son polimórficas; pueden aceptar un valor de cualquier tipo de lenguaje ECMAScript. Pero no se utilizan otros tipos de especificación con estas operaciones.
El tipo BigInt no tiene conversiones implícitas en el lenguaje ECMAScript; los programadores deben llamar a BigInt explícitamente para convertir valores de otros tipos.
ToPrimitive(hint)
Primero, necesitamos llamar a ToPrimitive
. Obviamente, si no tenemos un valor primitivo necesitamos convertirlo en uno.
Entonces, si tenemos un valor no primitivo, como un objeto, arrays, funciones etc.. necesitamos hacerlo primitivo
¿Como funciona?
En el, existen 2 métodos que están disponibles para cualquier tipo no primitivo (cualquier función, objeto, array, etc):
- hint: “number”:
Primero invoca valueOf()
y si regresa un primitivo, terminamos, si no me da un primitivo o no existe, entonces probamos toString()
, donde obtenemos un primitivo o no.
Si intentamos ambos, y no obtenemos un primitivo, obtendremos un error.
- hint: “string”:
Igual que en ejemplo anterior, solamente que funciona al revés, primero toString()
y después valueOf()
Si vas a utilizar un valor NO primitivo en algún lugar donde se requieren valores primitivos (como concatenación o matemáticas), tus valores van a pasar por el algoritmo ToPrimitive(hint)
ToString(argument)
La operación abstracta ToString, toma cualquier valor y devuelve la representación del valor en forma de string
Los resultados mostrados se pueden testear de la siguiente forma en la consola: String(argument)
Argument Type | Result |
---|---|
Undefined | Return “undefined”. |
Null | Return “null”. |
Boolean | If argument is true, return “true”. If argument is false, return “false”. |
Number | Return ! Number::toString(argument) . |
String | Return argument . |
Symbol | Throw a TypeError exception. |
BigInt | Return ! BigInt::toString(argument) . |
Object | Apply the following steps: |
1. Let primValue be ? ToPrimitive(argument, string) . |
|
2. Return ? ToString(primValue) . |
|
|
Pero ¿y si le pasamos un objeto?
Primero va a invocar a ToPrimitive(string)
con string hint.
|
|
ToNumber(argument)
Los resultados mostrados se pueden testear de la siguiente forma en la consola: Number(argument)
Argument Type | Result |
---|---|
Undefined | Return NaN. |
Null | Return +0𝔽. |
Boolean | If argument is true, return 1𝔽. If argument is false, return +0𝔽. |
Number | Return argument (no conversion). |
String | Return ! StringToNumber(argument) . |
Symbol | Throw a TypeError exception. |
BigInt | Throw a TypeError exception. |
Object | Apply the following steps: |
1. Let primValue be ? ToPrimitive(argument, number) . |
|
2. Return ? ToNumber(primValue) . |
|
|
Pero ¿y si le pasamos un objeto?
Primero va a invocar a ToPrimitive(number)
con number hint.
|
|
Ok, ¿qué paso aquí? Veamos el primer ejemplo:
Recordemos que primero se va a invocar ToPrimitive(number)
, donde obtendremos ""
, y al pasarlo a ToNumber, obtenemos 0
.
[""]
=> ""
=> 0
Para testear más valores, simplemente hay que usar esta pequeña función:
|
|
ToBoolean(argument)
Siempre que tengas cualquier valor que no sea Boolean y lo estes usando en donde se requiere un Boolean, este algoritmo se va a invocar.
El algoritmo solamente mira una tabla:
Argument Type | Result |
---|---|
Undefined | Return false. |
Null | Return false. |
Boolean | returnargument . |
Number | If argument is +0𝔽, -0𝔽, or NaN, return false; otherwise return true. |
String | If argument is the empty String (its length is 0), return false; otherwise return true. |
Symbol | Return true |
BigInt | If argument is 0ℤ, return false; otherwise return true. ` exception. |
Object | Return true |
|
|
Cuando se trabaja con Booleans, no ocurre otra coerción, nunca invocamos ToPrimitive, por eso, []
es true
Los signos
|
|
Es importante saber que cuando trabajamos con +
, se espera que se sumen numbers o strings, por eso, al momento de pasar valores no primitivos, como lo es []+[]
, obtenemos ""
pues se hace la coerción a string. Lo mismo sucede con 9+"1"
,
Al trabajar con -
, nuestros valores hacen coerción a number (y no a string o number, como con +
), es por esto por lo que 91-"1"
es 90
y "ex"-1
es NaN
NaN
NaN
es Not A Number
, pero es mejor pensar que es Invalid Number
, y por supuesto, NaN
es de tipo “number”.
NaN
es el único valor en todo el engine de JS que no es igual a sí mismo.
|
|
Para comparar NaN
(y otros valores), tenemos que usar Object.is
|
|