JavaScript Desmitificado: Coercion Parte 1

Publicado el 31 marzo 2014 por Codehero @codeheroblog

Lo más singular es que Javascript aplica coerción frente a nuestras narices sin nosotros darnos cuenta. Veamos algunos casos comunes, en los que esto ocurre:


Coerción a String

Para concatenar strings usamos el operador unitario (+, -, *, /), incluso lo usamos para concatenar strings con variables numéricas o números explícitos para formar mensajes más complejos.

console.log('Tengo ' + 10 + ' elefantes'); // => Tengo 10 elefantes

1 consolelog('Tengo '+10+' elefantes');// => Tengo 10 elefantes

En este caso Javascript forza al 10 a actuar como un string. Esto suena muy simple dicho de esta manera, el funcionamiento interno es el siguiente: Javascript llama a la función toString(). Esta función es parte de todos los objetos en Javascript ya que es heredada de Object. Si toString() no es capaz de retornar una representación primitiva (en este caso string), difiere la llamada a la función valueOf(), también heredada de Object. Si esta tampoco es capaz de retornar una representación primitiva, entonces lanza una “TypeError Exception”.


Coerción a Numero

Seguimos con más aplicaciones mágicas del operador unario. El trabajo de este operador es convertir a numero el operando que le sigue.

console.log(+'50'); // => 50 console.log(3 * '10'); // => 30 console.log(5 - '10'); // => -5

123 consolelog(+'50');// => 50consolelog(3*'10');// => 30consolelog(5-'10');// => -5

Y al igual que la conversión de string se basa en la interacción con los métodos toString() o valueOf(), sin embargo en este caso los llama al revés, primero a valueOf y luego a toString().


Coerción de acuerdo al contexto

Algunos objetos en javascript pueden ser forzados a trabajar con operadores unarios.

Utilizando los métodos valueOf() y toString() el objeto siendo forzado retorna un valor que tenga sentido según sea su aplicación.

El ejemplo más famoso es el del objeto Date.

console.log(+new Date()); // => 1396200768041 console.log(20 + +new Date()); // => 1396200768061

12 consolelog(+newDate());// => 1396200768041consolelog(20++newDate());// => 1396200768061

Este caso puede ser util para realizar operaciones, sin embargo hay ocasiones en las que es más util una representación en string.

console.log('La fecha de hoy es: ' + new Date()); // => 'La fecha de hoy es: Sun Mar 30 2014 13:09:26 GMT-0430 (VET)'

1 consolelog('La fecha de hoy es: '+newDate());// => 'La fecha de hoy es: Sun Mar 30 2014 13:09:26 GMT-0430 (VET)'

Entonces, los objetos forzados tienen la capacidad de retornar un valor según el contexto en el que se encuentren. En este caso, un valor numérico cuando utiliza en operaciones numéricas, y una representación en string para concatenación con strings.


Coercion de objetos propios

Tal cual como se forza el objeto Date, se debería poder hacer con los objetos creados por uno mismo. Resulta no ser tan fácil.

var Song = function (name, duration) { this.name = name; this.duration = duration; }; var mySong = new Song('R U Mine', 202); console.log(+mySong); // => NaN console.log("Duración: " + dollar); // => Duración: [object Object] // Ninguna de las dos representaciones es util. // Sobreescribamos toString() y valueOf() Song.prototype.toString = function () { return this.name; }; Song.prototype.valueOf = function () { return this.duration; }; console.log(+mySong); // => 202 console.log(mySong + ''); // => 202 console.log([mySong] + ''); // 'R U Mine'

12345678910111213141516171819202122232425 varSong=function(name,duration){  thisname=name;  thisduration=duration;}; varmySong=newSong('R U Mine',202);  consolelog(+mySong);// => NaNconsolelog("Duración: "+dollar);// => Duración: [object Object] // Ninguna de las dos representaciones es util.// Sobreescribamos toString() y valueOf() SongprototypetoString=function(){  returnthisname;}; SongprototypevalueOf=function(){  returnthisduration;}; consolelog(+mySong);// => 202consolelog(mySong+'');// => 202consolelog([mySong]+'');// 'R U Mine'

¿Por qué mySong + '' retorna el resultado de typeOf() en lugar del resultado de toString()?.

Javascript tiene problemas para poder determinar el valor por defecto de un objeto, necesita un indicio para poder decantar por un tipo, si no, asume que necesitas un numero. Es por eso que colocándolo entre corchetes (indicio) lo forza a string.


Comparación de tipos con coerción

El operador igual (=) también puede forzar los objetos a tipos primitivos mediante la prueba de equidad.

El presente ejemplo es extraído del libro “Expert Javascript” de Mark Daggett.

console.log([1] == 1); // => true console.log([1] == "1"); // => true console.log([{ toString: function () { return 1; } }] == "1"); // => true console.log([1] === 1); // => false console.log([1] === "1"); // => false console.log([{ toString: function () { return 1; } }] === "1"); // => false

12345678910111213141516171819 consolelog([1]==1);// => true consolelog([1]=="1");// => true consolelog([{  toString:function(){  return1;}}]=="1");// => true consolelog([1]===1);// => false consolelog([1]==="1");// => false consolelog([{  toString:function(){  return1;  }}]==="1");// => false


Cierre

En la próxima parte veremos otros tipos más complejos de coercion, por ahora me despido con lo que tenemos hasta aquí.

Hasta la próxima.