JavaScript nos permite trabajar con primitivas (cadenas, números, etc.) como si fueran objetos. También proporcionan métodos para llamar como tal. Los estudiaremos pronto, pero primero veremos cómo funciona porque, por supuesto, las primitivas no son objetos (y aquí lo dejaremos aún más claro).
Veamos las distinciones clave entre primitivos y objetos.
un primitivo
Es un valor de tipo primitivo.
Hay 7 tipos primitivos: string
, number
, bigint
, boolean
, symbol
, null
e undefined
.
un objeto
Es capaz de almacenar múltiples valores como propiedades.
Se puede crear con {}
, por ejemplo: {name: "John", age: 30}
. Hay otros tipos de objetos en JavaScript: las funciones, por ejemplo, son objetos.
Una de las mejores cosas de los objetos es que podemos almacenar una función como una de sus propiedades.
deja que juan = { nombre: "Juan", decir Hola: función() { alert("¡Hola amigo!"); } }; juan.diHola(); // ¡Hola amigo!
Así que aquí hemos creado un objeto john
con el método sayHi
.
Ya existen muchos objetos integrados, como los que trabajan con fechas, errores, elementos HTML, etc. Tienen diferentes propiedades y métodos.
¡Pero estas características tienen un costo!
Los objetos son "más pesados" que los primitivos. Requieren recursos adicionales para apoyar la maquinaria interna.
Aquí está la paradoja que enfrentó el creador de JavaScript:
Hay muchas cosas que uno querría hacer con una primitiva, como una cadena o un número. Sería genial acceder a ellos mediante métodos.
Los primitivos deben ser lo más rápidos y ligeros posible.
La solución parece un poco complicada, pero aquí está:
Los primitivos siguen siendo primitivos. Un valor único, según se desee.
El lenguaje permite el acceso a métodos y propiedades de cadenas, números, booleanos y símbolos.
Para que eso funcione, se crea un "envoltorio de objetos" especial que proporciona la funcionalidad adicional y luego se destruye.
Los “envoltorios de objetos” son diferentes para cada tipo primitivo y se denominan: String
, Number
, Boolean
, Symbol
y BigInt
. Por tanto, proporcionan diferentes conjuntos de métodos.
Por ejemplo, existe un método de cadena str.toUpperCase() que devuelve una str
en mayúscula.
Así es como funciona:
let str = "Hola"; alerta( str.toUpperCase() ); // HOLA
Sencillo, ¿verdad? Esto es lo que realmente sucede en str.toUpperCase()
:
La cadena str
es una primitiva. Entonces, en el momento de acceder a su propiedad, se crea un objeto especial que conoce el valor de la cadena y tiene métodos útiles, como toUpperCase()
.
Ese método se ejecuta y devuelve una nueva cadena (que se muestra mediante alert
).
El objeto especial se destruye, dejando la str
primitiva en paz.
Por tanto, las primitivas pueden proporcionar métodos, pero siguen siendo ligeras.
El motor JavaScript optimiza en gran medida este proceso. Incluso puede omitir la creación del objeto adicional. Pero aun así debe cumplir con la especificación y comportarse como si creara una.
Un número tiene sus propios métodos, por ejemplo, toFixed(n) redondea el número a la precisión dada:
sea n = 1,23456; alerta( n.toFixed(2) ); // 1.23
Veremos métodos más específicos en los capítulos Números y Cadenas.
Los constructores String/Number/Boolean
son solo para uso interno
Algunos lenguajes como Java nos permiten crear explícitamente "objetos contenedores" para primitivos usando una sintaxis como new Number(1)
o new Boolean(false)
.
En JavaScript, eso también es posible por razones históricas, pero no se recomienda en absoluto. Las cosas se volverán locas en varios lugares.
Por ejemplo:
alerta (tipo de 0); // "número" alerta (tipo de nuevo número (0)); // "objeto"!
Los objetos siempre son verdaderos en if
, por lo que aquí aparecerá la alerta:
let zero = nuevo Número(0); if (zero) { // cero es verdadero, porque es un objeto alert( "¡¿¡cero es verdad!?!" ); }
Por otro lado, usar las mismas funciones String/Number/Boolean
sin new
es algo totalmente bueno y útil. Convierten un valor al tipo correspondiente: a una cadena, un número o un booleano (primitivo).
Por ejemplo, esto es totalmente válido:
let num = Número("123"); // convierte una cadena en un número
nulo/indefinido no tiene métodos
Las primitivas especiales null
e undefined
son excepciones. No tienen "objetos contenedores" correspondientes y no proporcionan métodos. En cierto sentido, son "los más primitivos".
Un intento de acceder a una propiedad de tal valor daría el error:
alerta (prueba nula); // error
Las primitivas, excepto null
e undefined
proporcionan muchos métodos útiles. Los estudiaremos en los próximos capítulos.
Formalmente, estos métodos funcionan a través de objetos temporales, pero los motores de JavaScript están bien ajustados para optimizarlos internamente, por lo que no es costoso llamarlos.
importancia: 5
Considere el siguiente código:
let str = "Hola"; str.prueba = 5; alerta(str.prueba);
¿Qué opinas? ¿Funcionará? ¿Qué se mostrará?
Intenta ejecutarlo:
let str = "Hola"; str.prueba = 5; // (*) alerta(str.prueba);
Dependiendo de si tienes use strict
o no, el resultado puede ser:
undefined
(sin modo estricto)
Un error (modo estricto).
¿Por qué? Repitamos lo que está sucediendo en la línea (*)
:
Cuando se accede a una propiedad de str
, se crea un "objeto contenedor".
En modo estricto, escribir en él es un error.
De lo contrario, la operación con la propiedad se lleva a cabo, el objeto obtiene la propiedad test
, pero después de eso el "objeto contenedor" desaparece, por lo que en la última línea str
no tiene rastro de la propiedad.
Este ejemplo muestra claramente que los primitivos no son objetos.
No pueden almacenar datos adicionales.