A lo largo de esta serie de artículos, hemos estado hablando sobre la coerción de tipo, en qué se diferencia de la conversión de tipo y cómo se desempeña en idiomas tipificados dinámicamente..
Si solo te unes a la serie, consulta los artículos anteriores para asegurarte de estar al tanto de dónde estamos ahora:
Mientras que el otro artículo se centró en lenguajes de tipos débiles y tipos de datos a un alto nivel, veremos algunos ejemplos específicos de coerción de tipo en un lenguaje de tipo débil y los escollos que podemos experimentar sin saber cómo funciona la coacción de tipo. y como puede ser contraproducente.
Específicamente, veremos varios ejemplos utilizando JavaScript, y aunque los resultados que pueda ver a través del uso de los ejemplos no necesariamente se traducirán 1: 1 en otros idiomas, aún proporcionará un conjunto de pruebas que puede realizar lo que esté usando en sus proyectos cotidianos o en sus proyectos paralelos y evaluar los resultados que está viendo.
Podría decirse que uno de los problemas más comunes que ocurren en lenguajes de tipos débiles se presenta cada vez que hacemos comparaciones. Claro, hay otras ocasiones en que esperar que una variable sea de un tipo cuando realmente es otro puede afectarnos negativamente, pero los problemas más comunes ocurren cada vez que realizamos algún tipo de comparación.
Estas comparaciones pueden venir en forma de operaciones de igualdad, operaciones condicionales, operaciones a nivel de bits o durante interruptor / caja
operaciones.
Como se mencionó en artículos anteriores de esta serie, los diferentes idiomas tienen diferentes formas de coaccionar los tipos de datos, por lo que los ejemplos que vemos en este artículo pueden diferir un poco en el trabajo que realiza..
Es decir, vamos a ver estos ejemplos utilizando JavaScript, ya que es un lenguaje muy utilizado, pero las reglas siguen siendo aplicables en otros idiomas. Es solo que otros idiomas pueden colocar una prioridad diferente en un tipo de datos sobre otro, por lo que Los resultados de la coerción pueden ser un poco diferentes..
Entonces, dicho esto, comencemos a analizar cómo JavaScript maneja las comparaciones entre los tipos de datos utilizando el operador de igualdad (==
), el operador de igualdad estricta (===
), y cuando se utilizan valores como indefinido
y nulo
.
Antes de ver las comparaciones entre diferentes tipos de datos, tomemos un momento para observar que, en JavaScript, indefinido
y nulo
Son dos tipos diferentes de valores. Como si eso no fuera suficiente, puede ser aún más confuso al comparar los dos valores.
En primer lugar, tenga en cuenta lo siguiente:
typeof (indefinido)
en la consola, entonces el resultado sería indefinido
.typeof (nulo)
en la consola, entonces el resultado sería objeto
.A continuación, si declarara una variable sin asignarle realmente un valor, y evaluara su tipo, vería indefinido
.
/ ** * Declare una variable 'nombre' pero no le asigne un valor. * Ejecuta el resultado de 'typeof' en una consola y * se te dará 'indefinido'. * / nombre var; tipo de (nombre);
A continuación, digamos que optamos por inicializar la variable con un nulo
valor. Si tuvieras que evaluar la variable usando tipo de
te darían un objeto
resultado.
// Primero, declararemos la variable var número; / ** * En este punto, si tuviéramos que evaluar la variable * utilizando typeof, entonces se nos daría 'indefinido'. * / // Ahora asigne a la variable un valor de 'nulo' número = nulo; / ** * Y evaluar la variable. En este punto, * se nos devolverá el valor de 'objeto'. * / typeof (número);
¿Confuso? Recordemos de antes que eso en JavaScript, nulo
es un objeto
donde indefinido es su propio tipo - indefinido
.
Dicho esto, ahora podemos ver por qué las comparaciones pueden volverse difíciles cuando realizamos comparaciones en valores sin conocer explícitamente su tipo..
A lo largo de esta sección, analizaremos los resultados de la comparación de valores de diferentes tipos, pero veremos cómo se evalúan entre sí mediante comparaciones de igualdad y comparaciones estrictas de igualdad..
Tenga en cuenta que todos los ejemplos que enumeramos a continuación deben poder ejecutarse desde la consola de un navegador como Firebug o las herramientas de desarrollo de Chrome..
Para empezar, vamos a empezar con indefinido
y nulo
.
// Devuelve true undefined == null; nulo == indefinido; // Devuelve falso indefinido === nulo; nulo === indefinido;
Observe que en el primer caso, el operador de igualdad está devolviendo un valor de la comparación después realizando coerción tipo. Es decir, el intérprete está adivinando lo que queremos decir al realizar esta comparación.
En el segundo caso, estamos utilizando el operador de igualdad estricta. En este caso, no se produce ningún tipo de coerción. En cambio, toma los valores exactamente como son y los compara..
A continuación, echemos un vistazo a la declaración de una variable, no le asignamos un valor y luego ejecutamos una comparación.
// Declare la variable, no le asigne un valor var ejemplo; // Cuando se compara con undefined, devuelve true en ambos casos ejemplo == undefined; example === undefined // Cuando se compara con null, devuelve true o false example == null; // ejemplo verdadero === nulo; // false // Asigna un valor a la variable example = null; // Ahora haga un ejemplo de comparación estricta === null; // Devuelve true
Como puede ver, las cosas comienzan a complicarse un poco más cuando comenzamos a declarar y comparar variables con o sin valores..
Una vez que comencemos a introducir cadenas, números y valores booleanos, se puede complicar aún más. Primero, comencemos con cadenas y números. Comenzaremos declarando una variable con un valor de cadena de 42
y un número con el 42
y luego realizaremos nuestras comparaciones.
var sNumber, iNumber; sNumber = '42'; iNumber = 42; // Las comparaciones de igualdad dan como resultado sNumber == iNumber; // La comparación estricta produce un número falso === iNumber;
Nuevamente, observe que en el primer caso, el intérprete intenta forzar los valores de las variables y luego compararlos. En el primer caso, funciona: estamos comparando un valor de cadena de 42
a un valor numérico de 42
, pero cuando usamos la comparación de igualdad estricta y obtenemos falso
.
El segundo caso es técnicamente más preciso porque el primer valor es una cadena y el segundo es un número. La comparación de dos valores de diferentes tipos siempre debe producir falso.
Aunque hemos echado un vistazo a esto en un artículo anterior, ¿qué pasa con el caso de los números y los booleanos??
var iNumber, bBoolean; iNumber = 0; bBoolean = falso; // Devuelve true iNumber == bBoolean; // Devuelve false iNumber === bBoolean; // Devuelve true iNumber = 1; bBoolean = true; iNumber == bBoolean; // Devuelve false iNumber === bBoolean;
En este punto, debería comenzar a notar un patrón: cuando esté comparando valores de diferentes tipos, JavaScript puede forzar valores correctamente, pero produce el resultado más preciso cuando usa el operador de igualdad estricta.
Finalmente, veamos un ejemplo que combina cadenas, números y valores booleanos..
var sExample, iExample, bExample; sExample = '1'; iExample = 1; bExample = true; // Devuelve true sExample == iExample; // Devuelve el ejemplo falso === iExample; // Devuelve true iExample == bExample; // Devuelve false iExample === bExample; // Devuelve true sExample == bExample; // Devuelve el ejemplo falso === bExample;
Tenga en cuenta que estas son comparaciones básicas; sin embargo, cuando se hace en el contexto de un si / else
o si / else if / else
Usted ve cómo puede interrumpir el flujo de control a través de la condicional.
Tenga en cuenta que al realizar operaciones lógicas como &&
y ||
así como operadores bitwise como Y
y |
que las reglas de coerción todavía se aplican. Con ese fin, desea asegurarse de que cuando realice esas operaciones, utilice valores del mismo tipo para obtener los resultados más precisos..
De lo contrario, la coacción puede dar como resultado un falso positivo o un falso negativo.
Esto completa nuestra mirada rápida, para principiantes, sobre los tipos de datos y el tipo de coerción en idiomas tipificados dinámicamente. En última instancia, las reglas básicas son usar siempre operadores de igualdad estrictos y asegurarse de que las variables con las que está trabajando sean del mismo tipo. Si no está seguro, siempre puede convertirlos explícitamente utilizando las estrategias que describimos anteriormente en la serie..
A lo largo de esta serie, hemos analizado cómo varían y se comportan los tipos, desde lenguajes fuertemente tipados a lenguajes mal escritos. Hemos analizado en qué se diferencian la conversión y la coerción, y hemos examinado algunos de los posibles escollos que esto puede llevar a confiar demasiado en el intérprete o el compilador al realizar comparaciones..
Finalmente, echamos un vistazo a algunas estrategias sobre cómo escribir más código defensivo asegurándonos de que tenemos el tipo de datos que necesitamos y cómo utilizar operadores de comparación estrictos para asegurarnos de obtener los resultados que necesitamos..
Como se mencionó anteriormente, hemos utilizado JavaScript para los propósitos de nuestros ejemplos en esta serie de artículos, pero otros lenguajes de tipos débiles están sujetos a las mismas dificultades. La forma en que priorizan sus coerciones varía, pero las estrategias descritas en esta serie deberían ayudar a escribir un código más resistente cuando se trabaja en idiomas poco tipificados..