diff --git a/files/es/web/javascript/about_javascript/index.html b/files/es/web/javascript/about_javascript/index.html deleted file mode 100644 index 489247ef6fb97a..00000000000000 --- a/files/es/web/javascript/about_javascript/index.html +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: Acerca de JavaScript -slug: Web/JavaScript/About_JavaScript -tags: - - JavaScript -translation_of: Web/JavaScript/About_JavaScript -original_slug: Web/JavaScript/Acerca_de_JavaScript ---- -
JavaScript® (a menudo abreviado como JS) es un lenguaje ligero, interpretado y orientado a objetos con funciones de primera clase, y mejor conocido como el lenguaje de programación para las páginas Web, pero {{Interwiki("wikipedia", "JavaScript#Otras_características", "también se utiliza en muchos entornos que no son de navegador")}}. Es un lenguaje de scripts que es dinámico, multiparadigma, {{Interwiki("wikipedia", "Programación_basada_en_prototipos", "basado en prototipos")}} y admite estilos de programación orientados a objetos, imperativos y funcionales.
- -JavaScript se ejecuta en el lado del cliente de la web, y se puede utilizar para estilizar/programar cómo se comportan las páginas web cuando ocurre un evento. JavaScript es un potente lenguaje de scripts y fácil de aprender, ampliamente utilizado para controlar el comportamiento de las páginas web.
- -Contrariamente a la creencia popular, JavaScript no es "Java interpretado". En pocas palabras, JavaScript es un lenguaje de scripts dinámico que admite {{JSxRef("../Guide/Details_of_the_Object_Model", "construcción de objetos basada en prototipos", "#Lenguajes_basados_en_clases_vs._basados_en_prototipos")}}. Intencionalmente, la sintaxis básica es similar a Java y C++ para reducir la cantidad de conceptos nuevos necesarios para aprender el lenguaje. Construcciones del lenguaje, como las declaraciones if
, los bucles for
y while
, y switch
y los bloques try...catch
funcionan igual que en esos lenguajes (o casi).
JavaScript puede funcionar como un {{JSxRef("../Introduction_to_Object-Oriented_JavaScript", "lenguaje orientado a objetos")}} y {{Interwiki("wikipedia", "Programación_por_procedimientos", "procedimental")}}. Los objetos se crean mediante programación en JavaScript, adjuntando métodos y propiedades a objetos que de otro modo en tiempo de ejecución estarían vacíos, a diferencia de las definiciones de clases sintácticas comunes en lenguajes compilados como C++ y Java. Una vez que se ha construido un objeto, se puede utilizar como plano (o prototipo) para crear objetos similares.
- -Las capacidades dinámicas de JavaScript incluyen la construcción de objetos en tiempo de ejecución, listas de parámetros variables, variables de función, creación dinámica de scripts (a través de {{JSxRef("Objetos_globales/eval", "eval")}}, introspección de objetos (a través de for...in
) y recuperación de código fuente (los programas JavaScript pueden descompilar los cuerpos de las funciones en su texto fuente).
Para una explicación más profunda de la programación de JavaScript, sigue los enlaces recursos de JavaScript a continuación.
- -El proyecto Mozilla proporciona dos implementaciones de JavaScript. El primer JavaScript fue creado por Brendan Eich en Netscape, y a partir de entonces se ha actualizado para cumplir con ECMA-262 Edición 5 y versiones posteriores. Este motor, cuyo nombre en código es {{web.link("/es/docs/Mozilla/Projects/SpiderMonkey", "SpiderMonkey")}}, está implementado en C/C++. El motor {{web.link("/es/docs/Rhino", "Rhino")}}, creado principalmente por Norris Boyd (también en Netscape) es una implementación de JavaScript escrita en Java. Al igual que SpiderMonkey, Rhino también es compatible con ECMA-262 Edition 5.
- -Con el transcurso del tiempo, y tras varias importantes optimizaciones del entorno de ejecución como TraceMonkey (Firefox 3.5), JägerMonkey (Firefox 4) e IonMonkey se agregaron al motor de JavaScript SpiderMonkey. El trabajo siempre está en curso para mejorar el rendimiento de ejecución de JavaScript.
- -Más allá de las implementaciones anteriores, existen otros motores JavaScript populares como:—
- -Cada uno de los motores de JavaScript de Mozilla expone una API pública que los desarrolladores de aplicaciones pueden utilizar para integrar JavaScript en su software. Hasta ahora, el entorno de alojamiento más común para JavaScript son los navegadores web. Los navegadores web suelen utilizar la API pública para crear objetos del anfitrión responsables de reflejar el DOM en JavaScript.
- -Otra aplicación común para JavaScript es como lenguaje de programación de lado del servidor (Web). Un servidor web JavaScript expondría objetos del anfitrión que representan una solicitud HTTP y objetos de respuesta, que luego podría manipular un programa JavaScript para generar páginas web dinámicamente. Node.js es un ejemplo popular de esto.
- -JavaScript® es una marca comercial o una marca comercial registrada de Oracle en EE. UU. y otros países.
diff --git a/files/es/web/javascript/about_javascript/index.md b/files/es/web/javascript/about_javascript/index.md new file mode 100644 index 00000000000000..424927bd90bb53 --- /dev/null +++ b/files/es/web/javascript/about_javascript/index.md @@ -0,0 +1,54 @@ +--- +title: Acerca de JavaScript +slug: Web/JavaScript/About_JavaScript +tags: + - JavaScript +translation_of: Web/JavaScript/About_JavaScript +original_slug: Web/JavaScript/Acerca_de_JavaScript +--- +{{JsSidebar}} + +## ¿Qué es JavaScript? + +**JavaScript**® (a menudo abreviado como **JS**) es un lenguaje ligero, interpretado y orientado a objetos con [funciones de primera clase](https://en.wikipedia.org/wiki/First-class_function), y mejor conocido como el lenguaje de programación para las páginas Web, pero {{Interwiki("wikipedia", "JavaScript#Otras_características", "también se utiliza en muchos entornos que no son de navegador")}}. Es un lenguaje de scripts que es dinámico, multiparadigma, {{Interwiki("wikipedia", "Programación_basada_en_prototipos", "basado en prototipos")}} y admite estilos de programación orientados a objetos, imperativos y funcionales. + +JavaScript se ejecuta en el lado del cliente de la web, y se puede utilizar para estilizar/programar cómo se comportan las páginas web cuando ocurre un evento. JavaScript es un potente lenguaje de scripts y fácil de aprender, ampliamente utilizado para controlar el comportamiento de las páginas web. + +Contrariamente a la creencia popular, **JavaScript _no_ es "Java interpretado"**. En pocas palabras, JavaScript es un lenguaje de scripts dinámico que admite {{JSxRef("../Guide/Details_of_the_Object_Model", "construcción de objetos basada en prototipos", "#Lenguajes_basados_en_clases_vs._basados_en_prototipos")}}. Intencionalmente, la sintaxis básica es similar a Java y C++ para reducir la cantidad de conceptos nuevos necesarios para aprender el lenguaje. Construcciones del lenguaje, como las declaraciones `if`, los bucles `for` y `while`, y `switch` y los bloques `try...catch` funcionan igual que en esos lenguajes (o casi). + +JavaScript puede funcionar como un {{JSxRef("../Introduction_to_Object-Oriented_JavaScript", "lenguaje orientado a objetos")}} y {{Interwiki("wikipedia", "Programación_por_procedimientos", "procedimental")}}. Los objetos se crean mediante programación en JavaScript, adjuntando métodos y propiedades a objetos que de otro modo **en tiempo de ejecución** estarían vacíos, a diferencia de las definiciones de clases sintácticas comunes en lenguajes compilados como C++ y Java. Una vez que se ha construido un objeto, se puede utilizar como plano (o prototipo) para crear objetos similares. + +Las capacidades dinámicas de JavaScript incluyen la construcción de objetos en tiempo de ejecución, listas de parámetros variables, variables de función, creación dinámica de scripts (a través de {{JSxRef("Objetos_globales/eval", "eval")}}, introspección de objetos (a través de `for...in`) y recuperación de código fuente (los programas JavaScript pueden descompilar los cuerpos de las funciones en su texto fuente). + +Para una explicación más profunda de la programación de JavaScript, sigue los enlaces [recursos de JavaScript](#recursos_de_javascript) a continuación. + +## ¿Qué implementaciones de JavaScript están disponibles? + +El proyecto Mozilla proporciona dos implementaciones de JavaScript. El primer JavaScript **fue creado** por Brendan Eich en Netscape, y a partir de entonces se ha actualizado para cumplir con ECMA-262 Edición 5 y versiones posteriores. Este motor, cuyo nombre en código es {{web.link("/es/docs/Mozilla/Projects/SpiderMonkey", "SpiderMonkey")}}, está implementado en C/C++. El motor {{web.link("/es/docs/Rhino", "Rhino")}}, creado principalmente por Norris Boyd (también en Netscape) es una implementación de JavaScript escrita en Java. Al igual que SpiderMonkey, Rhino también es compatible con ECMA-262 Edition 5. + +Con el transcurso del tiempo, y tras varias importantes optimizaciones del entorno de ejecución como TraceMonkey (Firefox 3.5), JägerMonkey (Firefox 4) e IonMonkey se agregaron al motor de JavaScript SpiderMonkey. El trabajo siempre está en curso para mejorar el rendimiento de ejecución de JavaScript. + +Más allá de las implementaciones anteriores, existen otros motores JavaScript populares como:— + +- [V8](https://code.google.com/p/v8/) de Google , que se utiliza en el navegador Google Chrome y las versiones recientes del navegador Opera. Este también es el motor que utiliza [Node.js](http://nodejs.org). +- [JavaScriptCore](https://www.webkit.org/projects/javascript/index.html) (SquirrelFish/Nitro) utilizado en algunos navegadores WebKit como Apple Safari. +- [Carakan](http://my.opera.com/ODIN/blog/carakan-faq) en versiones antiguas de Opera. +- [Motor Chakra](http://en.wikipedia.org/wiki/Chakra_%28JScript_engine%29) utilizado en Internet Explorer (aunque el lenguaje que implementa formalmente se llama "JScript" para evitar problemas de marcas registradas). + +Cada uno de los motores de JavaScript de Mozilla expone una API pública que los desarrolladores de aplicaciones pueden utilizar para integrar JavaScript en su software. Hasta ahora, el entorno de alojamiento más común para JavaScript son los navegadores web. Los navegadores web suelen utilizar la API pública para crear **objetos del anfitrión** responsables de reflejar el [DOM](http://www.w3.org/DOM/) en JavaScript. + +Otra aplicación común para JavaScript es como lenguaje de programación de lado del servidor (Web). Un servidor web JavaScript expondría objetos del anfitrión que representan una solicitud HTTP y objetos de respuesta, que luego podría manipular un programa JavaScript para generar páginas web dinámicamente. [Node.js](http://nodejs.org) es un ejemplo popular de esto. + +## Recursos de JavaScript + +- {{web.link("/es/docs/Mozilla/Projects/SpiderMonkey", "SpiderMonkey")}} + - : Información específica sobre la implementación de JavaScript de Mozilla en el motor C/C++ (también conocido como SpiderMonkey), incluye cómo integrarlo en aplicaciones. + +- {{web.link("/es/docs/Rhino", "Rhino")}} + - : Información específica para la implementación de JavaScript escrita en Java (también conocido como Rhino). +- {{JSxRef("../Language_Resources", "Recursos del lenguaje")}} + - : Punteros a estándares JavaScript publicados. +- {{JSxRef("../A_re-introduction_to_JavaScript", "Una reintroducción a JavaScript")}} + - : {{JSxRef("../Guide", "Guía de JavaScript")}} y {{JSxRef("../Referencia", "Referencia de JavaScript")}}. + +**JavaScript®** es una marca comercial o una marca comercial registrada de Oracle en EE. UU. y otros países. diff --git a/files/es/web/javascript/closures/index.html b/files/es/web/javascript/closures/index.html deleted file mode 100644 index a84903a6fbb685..00000000000000 --- a/files/es/web/javascript/closures/index.html +++ /dev/null @@ -1,320 +0,0 @@ ---- -title: Closures -slug: Web/JavaScript/Closures -tags: - - Closures - - Guia(2) - - Guía - - JavaScript -translation_of: Web/JavaScript/Closures ---- -Una clausura o closure es una función que guarda referencias del estado adyacente (ámbito léxico). En otras palabras, una clausura permite acceder al ámbito de una función exterior desde una función interior. En JavaScript, las clausuras se crean cada vez que una función es creada.
- -Consideremos el siguiente ejemplo:
- - - -La función iniciar()
crea una variable local llamada nombre
y una función interna llamada mostrarNombre()
. Por ser una función interna, esta última solo está disponible dentro del cuerpo de iniciar()
. Notemos a su vez que mostrarNombre()
no tiene ninguna variable propia; pero, dado que las funciones internas tienen acceso a las variables de las funciones externas, mostrarNombre()
puede acceder a la variable nombre
declarada en la función iniciar()
.
Ejecuta el código usando este enlace de JSFiddle y observa que la sentencia alert()
, dentro de mostrarNombre()
, muestra con éxito el valor de la variable nombre
, la cual fue declarada en la función externa. Este es un ejemplo de ámbito léxico, el cual describe cómo un analizador sintáctico resuelve los nombres de las variables cuando hay funciones anidadas. La palabra léxico hace referencia al hecho de que el ámbito léxico se basa en el lugar donde una variable fue declarada para determinar dónde esta variable estará disponible. Las funciones anidadas tienen acceso a las variables declaradas en su ámbito exterior.
Considera el siguiente ejemplo:
- -function creaFunc() { - var nombre = "Mozilla"; - function muestraNombre() { - alert(nombre); - } - return muestraNombre; -} - -var miFunc = creaFunc(); -miFunc();- -
Si se ejecuta este código tendrá exactamente el mismo efecto que el ejemplo anterior: se mostrará el texto "Mozilla" en un cuadro de alerta de Javascript. Lo que lo hace diferente (e interesante) es que la función externa nos ha devuelto la función interna muestraNombre
()
antes de ejecutarla.
Puede parecer poco intuitivo que este código funcione. Normalmente, las variables locales dentro de una función sólo existen mientras dura la ejecución de dicha función. Una vez que creaFunc()
haya terminado de ejecutarse, es razonable suponer que no se pueda ya acceder a la variable nombre
. Dado que el código funciona como se esperaba, esto obviamente no es el caso.
La solución a este rompecabezas es que miFunc
se ha convertido en un closure. Un closure es un tipo especial de objeto que combina dos cosas: una función, y el entorno en que se creó esa función. El entorno está formado por las variables locales que estaban dentro del alcance en el momento que se creó el closure. En este caso, miFunc
es un closure que incorpora tanto la función muestraNombre
como el string "Mozilla" que existían cuando se creó el closure.
Este es un ejemplo un poco más interesante: una función creaSumador
:
function creaSumador(x) { - return function(y) { - return x + y; - }; -} - -var suma5 = creaSumador(5); -var suma10 = creaSumador(10); - -console.log(suma5(2)); // muestra 7 -console.log(suma10(2)); // muestra 12- -
En este ejemplo, hemos definido una función creaSumador
(x)
que toma un argumento único x
y devuelve una nueva función. Esa nueva función toma un único argumento y
, devolviendo la suma de x
+ y
.
En esencia, creaSumador
es una fábrica de función: crea funciones que pueden sumar un valor específico a su argumento. En el ejemplo anterior utilizamos nuestra fábrica de función para crear dos nuevas funciones: una que agrega 5 a su argumento y otra que agrega 10.
suma5
y suma10
son ambos closures. Comparten la misma definición de cuerpo de función, pero almacenan diferentes entornos. En el entorno suma5
, x
es 5. En lo que respecta a suma10
, x
es 10.
Hasta aquí hemos visto teoría, pero ¿son los closures realmente útiles? Vamos a considerar sus implicaciones prácticas. Un closure permite asociar algunos datos (el entorno) con una función que opera sobre esos datos. Esto tiene evidentes paralelismos con la programación orientada a objetos, en la que los objetos nos permiten asociar algunos datos (las propiedades del objeto) con uno o más métodos.
- -En consecuencia, puede utilizar un closure en cualquier lugar en el que normalmente pondría un objeto con un solo método.
- -En la web hay situaciones habituales en las que aplicarlos. Gran parte del código JavaScript para web está basado en eventos: definimos un comportamiento y lo conectamos a un evento que es activado por el usuario (como un click o pulsación de una tecla). Nuestro código generalmente se adjunta como una devolución de llamada (callback): que es una función que se ejecuta en respuesta al evento.
- -Aquí está un ejemplo práctico: Supongamos que queremos añadir algunos botones a una página para ajustar el tamaño del texto. Una manera de hacer esto es especificar el tamaño de fuente del elemento body
en píxeles y, a continuación, ajustar el tamaño de los demás elementos de la página (como los encabezados) utilizando la unidad relativa em
:
body { - font-family: Helvetica, Arial, sans-serif; - font-size: 12px; -} - -h1 { - font-size: 1.5em; -} -h2 { - font-size: 1.2em; -}- -
Nuestros botones interactivos de tamaño de texto pueden cambiar la propiedad font-size
del elemento body
, y los ajustes serán aplicados por los otros elementos de la página gracias a las unidades relativas.
Aquí está el código JavaScript:
- -function makeSizer(size) { - return function() { - document.body.style.fontSize = size + 'px'; - }; -} - -var size12 = makeSizer(12); -var size14 = makeSizer(14); -var size16 = makeSizer(16); -- -
size12
, size14
y size16
ahora son funciones que cambian el tamaño del texto de body
a 12, 14 y 16 pixels, respectivamente. Podemos conectarlos a botones (en este caso enlaces) de la siguiente forma:
document.getElementById('size-12').onclick = size12; -document.getElementById('size-14').onclick = size14; -document.getElementById('size-16').onclick = size16; -- -
<a href="#" id="size-12">12</a> -<a href="#" id="size-14">14</a> -<a href="#" id="size-16">16</a> -- -
Lenguajes como Java ofrecen la posibilidad de declarar métodos privados, es decir, que sólo pueden ser llamados por otros métodos en la misma clase.
- -JavaScript no proporciona una forma nativa de hacer esto, pero es posible emular métodos privados utilizando closures. Los métodos privados no son sólo útiles para restringir el acceso al código: también proporcionan una poderosa manera de administrar tu espacio de nombres global, evitando que los métodos no esenciales embrollen la interfaz pública de tu código.
- -Aquí vemos cómo definir algunas funciones públicas que pueden acceder a variables y funciones privadas utilizando closures. A esto se le conoce también como el patrón módulo:
- -var Counter = (function() { - var privateCounter = 0; - function changeBy(val) { - privateCounter += val; - } - return { - increment: function() { - changeBy(1); - }, - decrement: function() { - changeBy(-1); - }, - value: function() { - return privateCounter; - } - } -})(); - -alert(Counter.value()); /* Muestra 0 */ -Counter.increment(); -Counter.increment(); -alert(Counter.value()); /* Muestra 2 */ -Counter.decrement(); -alert(Counter.value()); /* Muestra 1 */- -
Hay mucho aquí. En los ejemplos anteriores cada closure ha tenido su propio entorno; aquí creamos un único entorno compartido por tres funciones: Counter.increment
, Counter.decrement
y Counter.value
.
El entorno compartido se crea en el cuerpo de una función anónima, que se ejecuta en el momento que se define. El entorno contiene dos elementos privados: una variable llamada privateCounter
y una función llamada changeBy
. No se puede acceder a ninguno de estos elementos privados directamente desde fuera de la función anónima. Se accede a ellos por las tres funciones públicas que se devuelven desde el contenedor anónimo.
Esas tres funciones públicas son closures que comparten el mismo entorno. Gracias al ámbito léxico de Javascript, cada uno de ellas tienen acceso a la variable privateCounter
y a la función changeBy.
En este caso hemos definido una función anónima que crea un contador, y luego la llamamos inmediatamente y asignamos el resultado a la variable Counter
. Pero podríamos almacenar esta función en una variable independiente y utilizarlo para crear varios contadores:
var makeCounter = function() { - var privateCounter = 0; - function changeBy(val) { - privateCounter += val; - } - return { - increment: function() { - changeBy(1); - }, - decrement: function() { - changeBy(-1); - }, - value: function() { - return privateCounter; - } - } -}; - -var Counter1 = makeCounter(); -var Counter2 = makeCounter(); -alert(Counter1.value()); /* Muestra 0 */ -Counter1.increment(); -Counter1.increment(); -alert(Counter1.value()); /* Muestra 2 */ -Counter1.decrement(); -alert(Counter1.value()); /* Muestra 1 */ -alert(Counter2.value()); /* Muestra 0 */- -
Ten en cuenta que cada uno de los dos contadores mantiene su independencia del otro. Su entorno durante la llamada de la función makeCounter()
es diferente cada vez. La variable del closure llamada privateCounter
contiene una instancia diferente cada vez.
Utilizar closures de este modo proporciona una serie de beneficios que se asocian normalmente con la programación orientada a objectos, en particular la encapsulación y la ocultación de datos.
- -Antes de la introducción de la palabra clave let
en JavaScript 1.7, un problema común con closures ocurría cuando se creaban dentro de un bucle 'loop'. Veamos el siguiente ejemplo:
<p id="help">Helpful notes will appear here</p> -<p>E-mail: <input type="text" id="email" name="email"></p> -<p>Name: <input type="text" id="name" name="name"></p> -<p>Age: <input type="text" id="age" name="age"></p> -- -
function showHelp(help) { - document.getElementById('help').innerHTML = help; -} - -function setupHelp() { - var helpText = [ - {'id': 'email', 'help': 'Dirección de correo electrónico'}, - {'id': 'name', 'help': 'Nombre completo'}, - {'id': 'age', 'help': 'Edad (debes tener más de 16 años)'} - ]; - - for (var i = 0; i < helpText.length; i++) { - var item = helpText[i]; - document.getElementById(item.id).onfocus = function() { - showHelp(item.help); - } - } -} - -setupHelp(); -- - - -
El array helpText
define tres avisos de ayuda, cada uno asociado con el ID de un campo de entrada en el documento. El bucle recorre estas definiciones, enlazando un evento onfocus a cada uno que muestra el método de ayuda asociada.
Si pruebas este código, verás que no funciona como esperabas. Independientemente del campo en el que se haga foco, siempre se mostrará el mensaje de ayuda relativo a la edad.
- -La razón de esto es que las funciones asignadas a onfocus son closures; que constan de la definición de la función y del entorno abarcado desde el ámbito de la función setupHelp
. Se han creado tres closures, pero todos comparten el mismo entorno. En el momento en que se ejecutan las funciones callback de onfocus, el bucle ya ha finalizado y la variable item
(compartida por los tres closures) ha quedado apuntando a la última entrada en la lista de helpText.
En este caso, una solución es utilizar más closures: concretamente añadiendo una fábrica de función como se ha descrito anteriormente:
- -function showHelp(help) { - document.getElementById('help').innerHTML = help; -} - -function makeHelpCallback(help) { - return function() { - showHelp(help); - }; -} - -function setupHelp() { - var helpText = [ - {'id': 'email', 'help': 'Dirección de correo electrónico'}, - {'id': 'name', 'help': 'Nombre completo'}, - {'id': 'age', 'help': 'Edad (debes tener más de 16 años)'} - ]; - - for (var i = 0; i < helpText.length; i++) { - var item = helpText[i]; - document.getElementById(item.id).onfocus = makeHelpCallback(item.help); - } -} - -setupHelp(); -- - - -
Esto funciona como se esperaba. En lugar de los tres callbacks compartiendo el mismo entorno, la función makeHelpCallback
crea un nuevo entorno para cada uno en el que help
se refiere a la cadena correspondiente del array helpText
.
No es aconsejable crear innecesariamente funciones dentro de otras funciones si no se necesitan los closures para una tarea particular ya que afectará negativamente el rendimiento del script tanto en consumo de memoria como en velocidad de procesamiento.
- -Por ejemplo, cuando se crea un nuevo objeto/clase, los métodos normalmente deberían asociarse al prototipo del objeto en vez de definirse en el constructor del objeto. La razón es que con este último sistema, cada vez que se llama al constructor (cada vez que se crea un objeto) se tienen que reasignar los métodos.
- -Veamos el siguente caso, que no es práctico pero sí demostrativo:
- -function MyObject(name, message) { - this.name = name.toString(); - this.message = message.toString(); - this.getName = function() { - return this.name; - }; - - this.getMessage = function() { - return this.message; - }; -} -- -
El código anterior no aprovecha los beneficios de los closures. Podríamos modificarlo de la siguiente manera:
- -function MyObject(name, message) { - this.name = name.toString(); - this.message = message.toString(); -} -MyObject.prototype = { - getName: function() { - return this.name; - }, - getMessage: function() { - return this.message; - } -}; -- -
Sin embargo, no se recomienda redefinir el prototipo, así que el siguiente ejemplo es aún mejor que el anterior, porque lo que hace es añadir funcionalidad al prototipo existente:
- -function MyObject(name, message) { - this.name = name.toString(); - this.message = message.toString(); -} -MyObject.prototype.getName = function() { - return this.name; -}; -MyObject.prototype.getMessage = function() { - return this.message; -}; -- -
En los dos ejemplos anteriores, todos los objetos comparten el prototipo heredado y no se van a definir los métodos cada vez que se crean de objetos. Ver Detalles del Modelo de Objetos para más información.
diff --git a/files/es/web/javascript/closures/index.md b/files/es/web/javascript/closures/index.md new file mode 100644 index 00000000000000..2baf1b42a94205 --- /dev/null +++ b/files/es/web/javascript/closures/index.md @@ -0,0 +1,339 @@ +--- +title: Closures +slug: Web/JavaScript/Closures +tags: + - Closures + - Guia(2) + - Guía + - JavaScript +translation_of: Web/JavaScript/Closures +--- +{{jsSidebar("Intermediate")}} + +Una clausura o _closure_ es una función que guarda referencias del estado adyacente (**ámbito léxico**). En otras palabras, una clausura permite acceder al ámbito de una función exterior desde una función interior. En JavaScript, las clausuras se crean cada vez que una función es creada. + +## Ámbito léxico + +Consideremos el siguiente ejemplo: + +```js +function iniciar() { + var nombre = "Mozilla"; // La variable nombre es una variable local creada por iniciar. + function mostrarNombre() { // La función mostrarNombre es una función interna, una clausura. + alert(nombre); // Usa una variable declarada en la función externa. + } + mostrarNombre(); +} +iniciar(); +``` + +La función `iniciar()` crea una variable local llamada `nombre` y una función interna llamada `mostrarNombre()`. Por ser una función interna, esta última solo está disponible dentro del cuerpo de `iniciar()`. Notemos a su vez que `mostrarNombre()` no tiene ninguna variable propia; pero, dado que las funciones internas tienen acceso a las variables de las funciones externas, `mostrarNombre()` puede acceder a la variable `nombre` declarada en la función `iniciar()`. + +Ejecuta el código usando [este enlace de JSFiddle](http://jsfiddle.net/xAFs9/3/) y observa que la sentencia `alert()`, dentro de `mostrarNombre()`, muestra con éxito el valor de la variable `nombre`, la cual fue declarada en la función externa. Este es un ejemplo de _ámbito léxico_, el cual describe cómo un analizador sintáctico resuelve los nombres de las variables cuando hay funciones anidadas. La palabra _léxico_ hace referencia al hecho de que el ámbito léxico se basa en el lugar donde una variable fue declarada para determinar dónde esta variable estará disponible. Las funciones anidadas tienen acceso a las variables declaradas en su ámbito exterior. + +## Clausuras + +Considera el siguiente ejemplo: + +```js +function creaFunc() { + var nombre = "Mozilla"; + function muestraNombre() { + alert(nombre); + } + return muestraNombre; +} + +var miFunc = creaFunc(); +miFunc(); +``` + +Si se ejecuta este código tendrá exactamente el mismo efecto que el ejemplo anterior: se mostrará el texto "Mozilla" en un cuadro de alerta de Javascript. Lo que lo hace diferente (e interesante) es que la función externa nos ha devuelto la función interna ` muestraNombre`` () `antes de ejecutarla. + +Puede parecer poco intuitivo que este código funcione. Normalmente, las variables locales dentro de una función sólo existen mientras dura la ejecución de dicha función. Una vez que `creaFunc()` haya terminado de ejecutarse, es razonable suponer que no se pueda ya acceder a la variable `nombre`. Dado que el código funciona como se esperaba, esto obviamente no es el caso. + +La solución a este rompecabezas es que `miFunc` se ha convertido en un _closure_. Un _closure_ es un tipo especial de objeto que combina dos cosas: una función, y el entorno en que se creó esa función. El entorno está formado por las variables locales que estaban dentro del alcance en el momento que se creó el closure. En este caso, `miFunc` es un closure que incorpora tanto la función `muestraNombre` como el string "Mozilla" que existían cuando se creó el closure. + +Este es un ejemplo un poco más interesante: una función `creaSumador`: + +```js +function creaSumador(x) { + return function(y) { + return x + y; + }; +} + +var suma5 = creaSumador(5); +var suma10 = creaSumador(10); + +console.log(suma5(2)); // muestra 7 +console.log(suma10(2)); // muestra 12 +``` + +En este ejemplo, hemos definido una función ` creaSumador``(x) ` que toma un argumento único `x` y devuelve una nueva función. Esa nueva función toma un único argumento `y`, devolviendo la suma de `x` + `y`. + +En esencia, ` creaSumador`` `es una fábrica de función: crea funciones que pueden sumar un valor específico a su argumento. En el ejemplo anterior utilizamos nuestra fábrica de función para crear dos nuevas funciones: una que agrega 5 a su argumento y otra que agrega 10. + +`suma5` y `suma10` son ambos closures. Comparten la misma definición de cuerpo de función, pero almacenan diferentes entornos. En el entorno `suma5`, `x` es 5. En lo que respecta a `suma10`, `x` es 10. + +## Closures prácticos + +Hasta aquí hemos visto teoría, pero ¿son los closures realmente útiles? Vamos a considerar sus implicaciones prácticas. Un closure permite asociar algunos datos (el entorno) con una función que opera sobre esos datos. Esto tiene evidentes paralelismos con la programación orientada a objetos, en la que los objetos nos permiten asociar algunos datos (las propiedades del objeto) con uno o más métodos. + +En consecuencia, puede utilizar un closure en cualquier lugar en el que normalmente pondría un objeto con un solo método. + +En la web hay situaciones habituales en las que aplicarlos. Gran parte del código JavaScript para web está basado en eventos: definimos un comportamiento y lo conectamos a un evento que es activado por el usuario (como un click o pulsación de una tecla). Nuestro código generalmente se adjunta como una devolución de llamada (callback): que es una función que se ejecuta en respuesta al evento. + +Aquí está un ejemplo práctico: Supongamos que queremos añadir algunos botones a una página para ajustar el tamaño del texto. Una manera de hacer esto es especificar el tamaño de fuente del elemento `body` en píxeles y, a continuación, ajustar el tamaño de los demás elementos de la página (como los encabezados) utilizando la unidad relativa `em`: + +```css +body { + font-family: Helvetica, Arial, sans-serif; + font-size: 12px; +} + +h1 { + font-size: 1.5em; +} +h2 { + font-size: 1.2em; +} +``` + +Nuestros botones interactivos de tamaño de texto pueden cambiar la propiedad `font-size` del elemento `body`, y los ajustes serán aplicados por los otros elementos de la página gracias a las unidades relativas. + +Aquí está el código JavaScript: + +```js +function makeSizer(size) { + return function() { + document.body.style.fontSize = size + 'px'; + }; +} + +var size12 = makeSizer(12); +var size14 = makeSizer(14); +var size16 = makeSizer(16); +``` + +`size12`, `size14` y `size16` ahora son funciones que cambian el tamaño del texto de `body` a 12, 14 y 16 pixels, respectivamente. Podemos conectarlos a botones (en este caso enlaces) de la siguiente forma: + +```js +document.getElementById('size-12').onclick = size12; +document.getElementById('size-14').onclick = size14; +document.getElementById('size-16').onclick = size16; +``` + +```html +12 +14 +16 +``` + +## Emulando métodos privados con closures + +Lenguajes como Java ofrecen la posibilidad de declarar métodos privados, es decir, que sólo pueden ser llamados por otros métodos en la misma clase. + +JavaScript no proporciona una forma nativa de hacer esto, pero es posible emular métodos privados utilizando closures. Los métodos privados no son sólo útiles para restringir el acceso al código: también proporcionan una poderosa manera de administrar tu espacio de nombres global, evitando que los métodos no esenciales embrollen la interfaz pública de tu código. + +Aquí vemos cómo definir algunas funciones públicas que pueden acceder a variables y funciones privadas utilizando closures. A esto se le conoce también como el [patrón módulo](http://www.google.com/search?q=javascript+patron+modulo "javascript patron modulo"): + +```js +var Counter = (function() { + var privateCounter = 0; + function changeBy(val) { + privateCounter += val; + } + return { + increment: function() { + changeBy(1); + }, + decrement: function() { + changeBy(-1); + }, + value: function() { + return privateCounter; + } + } +})(); + +alert(Counter.value()); /* Muestra 0 */ +Counter.increment(); +Counter.increment(); +alert(Counter.value()); /* Muestra 2 */ +Counter.decrement(); +alert(Counter.value()); /* Muestra 1 */ +``` + +Hay mucho aquí. En los ejemplos anteriores cada closure ha tenido su propio entorno; aquí creamos un único entorno compartido por tres funciones: `Counter.increment`, `Counter.decrement` y `Counter.value`. + +El entorno compartido se crea en el cuerpo de una función anónima, que se ejecuta en el momento que se define. El entorno contiene dos elementos privados: una variable llamada `privateCounter` y una función llamada `changeBy`. No se puede acceder a ninguno de estos elementos privados directamente desde fuera de la función anónima. Se accede a ellos por las tres funciones públicas que se devuelven desde el contenedor anónimo. + +Esas tres funciones públicas son closures que comparten el mismo entorno. Gracias al ámbito léxico de Javascript, cada uno de ellas tienen acceso a la variable `privateCounter` y a la función `changeBy.` + +En este caso hemos definido una función anónima que crea un contador, y luego la llamamos inmediatamente y asignamos el resultado a la variable `Counter`. Pero podríamos almacenar esta función en una variable independiente y utilizarlo para crear varios contadores: + +```js +var makeCounter = function() { + var privateCounter = 0; + function changeBy(val) { + privateCounter += val; + } + return { + increment: function() { + changeBy(1); + }, + decrement: function() { + changeBy(-1); + }, + value: function() { + return privateCounter; + } + } +}; + +var Counter1 = makeCounter(); +var Counter2 = makeCounter(); +alert(Counter1.value()); /* Muestra 0 */ +Counter1.increment(); +Counter1.increment(); +alert(Counter1.value()); /* Muestra 2 */ +Counter1.decrement(); +alert(Counter1.value()); /* Muestra 1 */ +alert(Counter2.value()); /* Muestra 0 */ +``` + +Ten en cuenta que cada uno de los dos contadores mantiene su independencia del otro. Su entorno durante la llamada de la función `makeCounter()` es diferente cada vez. La variable del closure llamada `privateCounter `contiene una instancia diferente cada vez. + +Utilizar closures de este modo proporciona una serie de beneficios que se asocian normalmente con la programación orientada a objectos, en particular la encapsulación y la ocultación de datos. + +## Creando closures en loops: Un error común + +Antes de la introducción de la palabra clave [`let`](/es/docs/JavaScript/Reference/Statements/let "let") en JavaScript 1.7, un problema común con closures ocurría cuando se creaban dentro de un bucle 'loop'. Veamos el siguiente ejemplo: + +```html +Helpful notes will appear here
+E-mail:
+Name:
+Age:
+``` + +```js +function showHelp(help) { + document.getElementById('help').innerHTML = help; +} + +function setupHelp() { + var helpText = [ + {'id': 'email', 'help': 'Dirección de correo electrónico'}, + {'id': 'name', 'help': 'Nombre completo'}, + {'id': 'age', 'help': 'Edad (debes tener más de 16 años)'} + ]; + + for (var i = 0; i < helpText.length; i++) { + var item = helpText[i]; + document.getElementById(item.id).onfocus = function() { + showHelp(item.help); + } + } +} + +setupHelp(); +``` + +[Ver en el JSFiddle](https://jsfiddle.net/v7gjv) + +El array `helpText` define tres avisos de ayuda, cada uno asociado con el ID de un campo de entrada en el documento. El bucle recorre estas definiciones, enlazando un evento onfocus a cada uno que muestra el método de ayuda asociada. + +Si pruebas este código, verás que no funciona como esperabas. Independientemente del campo en el que se haga foco, siempre se mostrará el mensaje de ayuda relativo a la edad. + +La razón de esto es que las funciones asignadas a onfocus son closures; que constan de la definición de la función y del entorno abarcado desde el ámbito de la función `setupHelp`. Se han creado tres closures, pero todos comparten el mismo entorno. En el momento en que se ejecutan las funciones callback de onfocus, el bucle ya ha finalizado y la variable `item` (compartida por los tres closures) ha quedado apuntando a la última entrada en la lista de `helpText.` + +En este caso, una solución es utilizar más closures: concretamente añadiendo una fábrica de función como se ha descrito anteriormente: + +```js +function showHelp(help) { + document.getElementById('help').innerHTML = help; +} + +function makeHelpCallback(help) { + return function() { + showHelp(help); + }; +} + +function setupHelp() { + var helpText = [ + {'id': 'email', 'help': 'Dirección de correo electrónico'}, + {'id': 'name', 'help': 'Nombre completo'}, + {'id': 'age', 'help': 'Edad (debes tener más de 16 años)'} + ]; + + for (var i = 0; i < helpText.length; i++) { + var item = helpText[i]; + document.getElementById(item.id).onfocus = makeHelpCallback(item.help); + } +} + +setupHelp(); +``` + +[Ver en el JSFiddle](https://jsfiddle.net/v7gjv/1) + +Esto funciona como se esperaba. En lugar de los tres callbacks compartiendo el mismo entorno, la función `makeHelpCallback` crea un nuevo entorno para cada uno en el que `help` se refiere a la cadena correspondiente del array `helpText`. + +## Consideraciones de rendimiento + +No es aconsejable crear innecesariamente funciones dentro de otras funciones si no se necesitan los closures para una tarea particular ya que afectará negativamente el rendimiento del script tanto en consumo de memoria como en velocidad de procesamiento. + +Por ejemplo, cuando se crea un nuevo objeto/clase, los métodos normalmente deberían asociarse al prototipo del objeto en vez de definirse en el constructor del objeto. La razón es que con este último sistema, cada vez que se llama al constructor (cada vez que se crea un objeto) se tienen que reasignar los métodos. + +Veamos el siguente caso, que no es práctico pero sí demostrativo: + +```js +function MyObject(name, message) { + this.name = name.toString(); + this.message = message.toString(); + this.getName = function() { + return this.name; + }; + + this.getMessage = function() { + return this.message; + }; +} +``` + +El código anterior no aprovecha los beneficios de los closures. Podríamos modificarlo de la siguiente manera: + +```js +function MyObject(name, message) { + this.name = name.toString(); + this.message = message.toString(); +} +MyObject.prototype = { + getName: function() { + return this.name; + }, + getMessage: function() { + return this.message; + } +}; +``` + +Sin embargo, no se recomienda redefinir el prototipo, así que el siguiente ejemplo es aún mejor que el anterior, porque lo que hace es añadir funcionalidad al prototipo existente: + +```js +function MyObject(name, message) { + this.name = name.toString(); + this.message = message.toString(); +} +MyObject.prototype.getName = function() { + return this.name; +}; +MyObject.prototype.getMessage = function() { + return this.message; +}; +``` + +En los dos ejemplos anteriores, todos los objetos comparten el prototipo heredado y no se van a definir los métodos cada vez que se crean de objetos. Ver [Detalles del Modelo de Objetos](/es/docs/Web/JavaScript/Guide/Details_of_the_Object_Model "en-US/docs/JavaScript/Guide/Details of the Object Model") para más información. diff --git a/files/es/web/javascript/data_structures/index.html b/files/es/web/javascript/data_structures/index.html deleted file mode 100644 index 5a75d6a883004c..00000000000000 --- a/files/es/web/javascript/data_structures/index.html +++ /dev/null @@ -1,452 +0,0 @@ ---- -title: Tipos de datos y estructuras en JavaScript -slug: Web/JavaScript/Data_structures -tags: - - JavaScript - - Novato - - Principiante - - Tipado -translation_of: Web/JavaScript/Data_structures ---- -Todos los lenguajes de programación tienen estructuras de datos integradas, pero estas a menudo difieren de un lenguaje a otro. Este artículo intenta enumerar las estructuras de datos integradas disponibles en JavaScript y las propiedades que tienen. Estas se pueden utilizar para construir otras estructuras de datos. Siempre que es posible, se hacen comparaciones con otros lenguajes.
- -JavaScript es un lenguaje débilmente tipado y dinámico. Las variables en JavaScript no están asociadas directamente con ningún tipo de valor en particular, y a cualquier variable se le puede asignar (y reasignar) valores de todos los tipos:
- -let foo = 42; // foo ahora es un número -foo = 'bar'; // foo ahora es un string -foo = true; // foo ahora es un booleano -- -
El último estándar ECMAScript define nueve tipos:
- -typeof instance === "undefined"
typeof instance === "boolean"
typeof instance === "number"
typeof instance === "string"
typeof instance === "bigint"
typeof instance === "symbol"
typeof instance === "object"
. Tipo {{Glossary("Primitive", "primitivo")}} especial que tiene un uso adicional para su valor: si el objeto no se hereda, se muestra null
;typeof instance === "object"
. Tipo estructural especial que no es de datos pero para cualquier instancia de objeto construido que también se utiliza como estructuras de datos: new {{jsxref("Object")}}, new {{jsxref("Array")}}, new {{jsxref("Map")}}, new {{jsxref("Set")}}, new {{jsxref("WeakMap")}}, new {{jsxref("WeakSet")}}, new {{jsxref("Date")}} y casi todo lo hecho con la palabra clave new
;typeof
: typeof instance === "function"
. Esta simplemente es una forma abreviada para funciones, aunque cada constructor de funciones se deriva del constructor Object
.Ten en cuenta que el único propósito valioso del uso del operador typeof
es verificar el tipo de dato. Si deseamos verificar cualquier Tipo Estructural derivado de Object
, no tiene sentido usar typeof
para eso, ya que siempre recibiremos "object
". La forma correcta de comprobar qué tipo de Objeto estamos usando es la palabra clave {{jsxref("Operators/instanceof", "instanceof")}}. Pero incluso en ese caso, puede haber conceptos erróneos.
Todos los tipos, excepto los objetos, definen valores inmutables (es decir, valores que no se pueden cambiar). Por ejemplo (y a diferencia de C), las cadenas son inmutables. Nos referimos a los valores de estos tipos como "valores primitivos".
- -Boolean
Boolean
representa una entidad lógica y puede tener dos valores: true
y false
. Consulta {{Glossary("Boolean")}} y {{jsxref("Boolean")}} para obtener más detalles.
Null
El tipo Null
tiene exactamente un valor: null
. Consulta {{jsxref("null")}} y {{Glossary("Null")}} para obtener más detalles.
Undefined
Una variable a la que no se le ha asignado un valor tiene el valor undefined
. Consulta {{jsxref("undefined")}} y {{Glossary("Undefined")}} para obtener más detalles.
Number
ECMAScript tiene dos tipos numéricos integrados: Number
y BigInt
(ve más abajo).
El tipo Number
es un valor en formato binario de 64 bits de doble precisión IEEE 754 (números entre -(253 - 1) y 253 - 1). Además de representar números de punto flotante, el tipo Number
tiene tres valores simbólicos: +Infinity
, -Infinity
y {{jsxref("NaN")}} ("Not a Number" o No es un número).
Para verificar el valor disponible más grande o el valor más pequeño disponible dentro de {{jsxref("Infinity", "±Infinity")}}, puedes usar las constantes {{jsxref("Number.MAX_VALUE")}} o {{jsxref("Number.MIN_VALUE")}}.
- -A partir de ECMAScript 2015, también puedes comprobar si un número está en el rango de números de punto flotante de doble precisión mediante {{jsxref("Number.isSafeInteger()")}} así como {{jsxref("Number.MAX_SAFE_INTEGER")}} y {{jsxref("Number.MIN_SAFE_INTEGER")}}.
- -Más allá de este rango, los enteros en JavaScript ya no son seguros y serán una aproximación de punto flotante de doble precisión del valor.
-El tipo number
solo tiene un entero con dos representaciones: 0
se representa como -0
y +0
. (0
es un alias de +0
).
En la praxis, esto casi no tiene impacto. Por ejemplo, +0 === -0
es true
. Sin embargo, puedes notar esto cuando divides entre cero:
> 42 / +0 -Infinity -> 42 / -0 --Infinity -- -
Aunque un number
a menudo representa solo su valor, JavaScript proporciona {{jsxref("Operators/Bitwise_Operators", "operadores binarios (bitwise)")}}.
Precaución: Aunque los operadores bit a bit se pueden usar para representar múltiples valores Booleanos dentro de un solo número usando el enmascaramiento de bits, esto generalmente se considera una mala práctica. JavaScript ofrece otros medios para representar un conjunto de valores booleanos (como un arreglo de valores booleanos o un objeto con valores booleanos asignados a propiedades con nombre). El enmascaramiento de bits también tiende a hacer que el código sea más difícil de leer, comprender y mantener.
-Posiblemente sea necesario utilizar estas técnicas en entornos muy restringidos, como cuando se intenta hacer frente a las limitaciones del almacenamiento local, o en casos extremos (como cuando cada bit de la red cuenta). Esta técnica solo se debe considerar cuando sea la última medida que se pueda tomar para optimizar el tamaño.
- -BigInt
El tipo {{jsxref("BigInt")}} es un primitivo numérico en JavaScript que puede representar números enteros con precisión arbitraria. Con BigInt
s, puedes almacenar y operar de forma segura en números enteros grandes incluso más allá del límite seguro de enteros para Number
s.
Un BigInt
se crea agregando n
al final de un número entero o llamando al constructor.
Puedes obtener el valor más seguro que se puede incrementar con Number
s utilizando la constante {{jsxref("Number.MAX_SAFE_INTEGER")}}. Con la introducción de BigInt
s, puedes operar con números más allá de {{jsxref("Number.MAX_SAFE_INTEGER")}}.
Este ejemplo demuestra, dónde, incrementando el {{jsxref("Number.MAX_SAFE_INTEGER")}} devuelve el resultado esperado:
- -> const x = 2n ** 53n; -9007199254740992n -> const y = x + 1n; -9007199254740993n -- -
Puedes utilizar los operadores +
, *
, -
, **
y %
con BigInt
s, igual que con Number
s. Un BigInt
no es estrictamente igual a un Number
, pero lo es en términos generales.
Un BigInt
se comporta como un Number
en los casos en que se convierte a Boolean
: if
, ||
, &&
, Boolean
, !
.
Los BigInt
no se pueden utilizar indistintamente con los Number
. En su lugar, se lanzará un {{jsxref("TypeError")}}.
String
El tipo {{jsxref("String")}} de JavaScript se utiliza para representar datos textuales. Es un conjunto de "elementos" de valores enteros sin signo de 16 bits. Cada elemento del String
ocupa una posición en la cadena. El primer elemento está en el índice 0
, el siguiente en el índice 1
, y así sucesivamente. La longitud de una cadena es el número de elementos que contiene.
A diferencia de algunos lenguajes de programación (tal como C), las cadenas de JavaScript son inmutables. Esto significa que una vez que se crea una cadena, no es posible modificarla.
- -Sin embargo, todavía es posible crear otra cadena basada en una operación en la cadena original. Por ejemplo:
- -+
) o {{jsxref("String.concat()")}}.Puede resultar tentador utilizar cadenas para representar datos complejos. Hacer esto viene con beneficios a corto plazo:
- -input
s—, valores de almacenamiento local, respuestas XMLHttpRequest
cuando se usa responseText
, etc.) y puede resultar tentador trabajar solo con cadenas.Con las convenciones, es posible representar cualquier estructura de datos en una cadena. Esto no la convierte en una buena idea. Por ejemplo, con un separador, se podría emular una lista (mientras que un arreglo de JavaScript sería más adecuado). Desafortunadamente, cuando el separador se usa en uno de los elementos de la "lista", la lista se rompe. Se puede elegir un caracter de escape, etc. Todo esto requiere convenciones y crea una innecesaria carga de mantenimiento.
- -Utiliza cadenas para datos textuales. Cuando quieras representar datos complejos, procesa las cadenas y usa la abstracción adecuada.
- -Symbol
Un símbolo es un valor primitivo único e inmutable y se puede utilizar como clave de una propiedad de objeto (ve más abajo). En algunos lenguajes de programación, los símbolos se denominan "átomos".
- -Para obtener más detalles, consulta {{Glossary("Symbol")}} y el contenedor de objetos {{jsxref("Symbol")}} en JavaScript.
- -En ciencias de la computación, un objeto es un valor en la memoria al que posiblemente hace referencia un {{Glossary("Identifier", "identificador")}}.
- -En JavaScript, los objetos se pueden ver como una colección de propiedades. Con la sintaxis de objeto literal, se inicia un conjunto limitado de propiedades; luego se pueden agregar y eliminar propiedades. Los valores de propiedad pueden ser valores de cualquier tipo, incluidos otros objetos, lo que permite construir estructuras de datos complejas. Las propiedades se identifican mediante valores clave. Un valor clave es un valor de cadena o un símbolo.
- -Hay dos tipos de propiedades de objeto que tienen ciertos atributos: la propiedad data y la propiedad accessor.
- -Nota: Cada propiedad tiene atributos correspondientes. Los atributos, internamente los utiliza el motor JavaScript, por lo que no puedes acceder a ellos directamente. Es por eso que los atributos se enumeran entre corchetes dobles, en lugar de simples.
- -Consulta {{jsxref("Object.defineProperty()")}} para obtener más información.
-Data
Asocia una clave con un valor y tiene los siguientes atributos:
- -Atributo | -Tipo | -Descripción | -Valor predeterminado | -
---|---|---|---|
[[Value]] | -Cualquier tipo de JavaScript | -El valor recuperado por un captador de acceso get a la propiedad. |
- undefined |
-
[[Writable]] | -Boolean |
- Si es false , el [[Value]] de la propiedad no se puede cambiar. |
- false |
-
[[Enumerable]] | -Boolean |
-
- Si es |
- false |
-
[[Configurable]] | -Boolean |
- Si es false , la propiedad no se puede eliminar, no se puede cambiar a una propiedad de acceso descriptor y los atributos que no sean [[Value]] y [[Writable]] no se pueden cambiar. |
- false |
-
Atributo | -Tipo | -Descripción | -
---|---|---|
Read-only |
- Boolean |
- Estado inverso del atributo ES5 [[Writable]]. | -
DontEnum |
- Boolean |
- Estado inverso del atributo ES5 [[Enumerable]]. | -
DontDelete |
- Boolean |
- Estado inverso del atributo ES5 [[Configurable]]. | -
Accessor
Asocia una clave con una de las dos funciones de acceso (get
y set
) para recuperar o almacenar un valor y tiene los siguientes atributos:
Atributo | -Tipo | -Descripción | -Valor predeterminado | -
---|---|---|---|
[[Get]] | -Objeto Function o undefined |
- La función se llama con una lista de argumentos vacía y recupera el valor de la propiedad cada vez que se realiza un acceso al valor. - Consulta también get . |
- undefined |
-
[[Set]] | -Objeto Function o undefined |
- La función se llama con un argumento que contiene el valor asignado y se ejecuta siempre que se intenta cambiar una propiedad específica. - Consulta también set . |
- undefined |
-
[[Enumerable]] | -Boolean |
- Si es true , la propiedad se enumerará en bucles for...in . |
- false |
-
[[Configurable]] | -Boolean |
- Si es false , la propiedad no se puede eliminar y no se puede cambiar a una propiedad de datos. |
- false |
-
Un objeto JavaScript es una asociación entre claves y valores. Las claves son cadenas (o {{jsxref("Symbol")}}s), y los valores pueden ser cualquier cosa. Esto hace que los objetos se ajusten naturalmente a hashmaps
.
Las funciones son objetos regulares con la capacidad adicional de ser invocables.
- -Al representar fechas, la mejor opción es utilizar la utilidad Date
incorporada en JavaScript.
Los arreglos son objetos regulares para los que existe una relación particular entre las propiedades de clave entera y la Propiedad length
.
Además, los arreglos heredan de Array.prototype
, que les proporciona un puñado de convenientes métodos para manipular arreglos. Por ejemplo, indexOf
(buscando un valor en el arreglo) o push
(agrega un elemento al arreglo), y así sucesivamente. Esto hace que el Array
sea un candidato perfecto para representar listas o conjuntos.
Los Arreglos tipados son nuevos en JavaScript con ECMAScript 2015 y presentan una vista similar a un arreglo de un búfer de datos binarios subyacente. La siguiente tabla ayuda a determinar los tipos de datos equivalentes en C:
- -Tipo | -Intervalo de valores | -Tamaño en bytes | -Descripción | -Tipo de IDL web | -Tipo C equivalente | -
---|---|---|---|---|---|
{{jsxref("Int8Array")}} | --128 a 127 |
- 1 | -Dos enteros complementarios de 8 bits con signo | -byte |
- int8_t |
-
{{jsxref("Uint8Array")}} | -0 a 255 |
- 1 | -Entero de 8-bit sin signo | -octet |
- uint8_t |
-
{{jsxref("Uint8ClampedArray")}} | -0 a 255 |
- 1 | -Entero de 8 bits sin signo (sujeto) | -octet |
- uint8_t |
-
{{jsxref("Int16Array")}} | --32768 a 32767 |
- 2 | -Dos enteros complementarios de 16 bits con signo | -short |
- int16_t |
-
{{jsxref("Uint16Array")}} | -0 a 65535 |
- 2 | -Entero de 16 bits sin signo | -Short sin signo |
- uint16_t |
-
{{jsxref("Int32Array")}} | --2147483648 a 2147483647 |
- 4 | -dos enteros complementarios de 32 bits con signo | -long |
- int32_t |
-
{{jsxref("Uint32Array")}} | -0 a 4294967295 |
- 4 | -Enteros de 32 bits sin signo | -long sin signo |
- uint32_t |
-
{{jsxref("Float32Array")}} | -1.2 ×10-38 a 3.4 ×1038 |
- 4 | -Número de coma flotante IEEE de 32 bits (7 dígitos significativos, p. ej., 1.1234567 ) |
- float sin restricciones |
- float |
-
{{jsxref("Float64Array")}} | -5.0 ×10-324 a 1.8 ×10308 |
- 8 | -Número de coma flotante IEEE de 64 bits (16 dígitos significativos, p. ej., 1.123...15 ) |
- doble sin restricciones |
- double |
-
{{jsxref("BigInt64Array")}} | --263 a 263-1 |
- 8 | -Dos enteros complementarios de 64 bits con signo | -bigint |
- int64_t (long long con signo) |
-
{{jsxref("BigUint64Array")}} | -0 a 264-1 |
- 8 | -Entero de 64 bits sin signo | -bigint |
- uint64_t (long long sin signo) |
-
WeakMaps
, WeakSets
Estas estructuras de datos, introducidas en ECMAScript Edition 6, toman referencias a objetos como claves. {{jsxref("Set")}} y {{jsxref("WeakSet")}} representan un conjunto de objetos, mientras que {{jsxref("Map")}} y {{jsxref("WeakMap")}} se asocian un valor a un objeto.
- -La diferencia entre Map
s y WeakMap
s es que en el primero, las claves de objeto se pueden enumerar. Esto permite la optimización de la recolección de basura en el último caso.
Se podrían implementar Map
s y Set
s en ECMAScript 5 puro. Sin embargo, dado que los objetos no se pueden comparar (en el sentido de <
"menor que", por ejemplo), el rendimiento de búsqueda sería necesariamente lineal. Las implementaciones nativas de ellos (incluidos los WeakMap
s) pueden tener un rendimiento de búsqueda que es aproximadamente logarítmico al tiempo constante.
Por lo general, para vincular datos a un nodo DOM, se pueden establecer propiedades directamente en el objeto o usar atributos data-*
. Esto tiene la desventaja de que los datos están disponibles para cualquier script que se ejecute en el mismo contexto. Los Map
s y WeakMap
s facilitan la vinculación privada de datos a un objeto.
JSON (Java Script Object Notation) es un formato ligero de intercambio de datos, derivado de JavaScript, pero utilizado por muchos lenguajes de programación. JSON crea estructuras de datos universales.
- -Consulta {{Glossary("JSON")}} y {{jsxref("JSON")}} para obtener más detalles.
- -JavaScript tiene una biblioteca estándar de objetos integrados.
- -Échale un vistazo a la referencia para conocer más objetos.
- -typeof
El operador typeof
te puede ayudar a encontrar el tipo de tu variable.
Lee la página de referencia para obtener más detalles y casos extremos.
- -Especificación | -
---|
{{SpecName('ESDraft', '#sec-ecmascript-data-types-and-values', 'Tipos Data y Values ECMAScript')}} | -
Las siguientes secciones explican un modelo teórico. Los motores modernos de JavaScript implementan y optimizan fuertemente la semántica descrita a continuación.
- -Las llamadas a función forman una pila de frames. Un frame encapsula información como el contexto y las variables locales de una función.
- -function f(b){ - var a = 12; - return a+b+35; -} - -function g(x){ - var m = 4; - return f(m*x); -} - -g(21); -- -
Cuando se llama a g
, un primer frame es creado, el cual contiene g
argumentos y variables locales. Cuando g
llama a f
, un segundo frame es creado y colocado encima del primero, con f
argumentos y variables locales. Cuando f
termina de ejecutarse, el último frame (en este caso f
) es sacado de la pila (déjando solo el frame de g
). Cuando g
termina de ejecutarse, la pila está vacía.
Los objetos son colocados en un montículo, el cual, como su nombre lo dice, denota una gran región de memoria, mayormente sin estructura u orden.
- -Un programa en ejecución en JavaScript contiene una cola de mensajes, la cual es una lista de mensajes a ser procesados. Cada mensaje se asocia con una función. Cuando la pila está vacía, un mensaje es sacado de la cola y procesado. Procesar un mensaje consiste en llamar a la función asociada al mensaje (y por ende crear una frame en la pila). El mensaje procesado termina cuando la pila está vacía de nuevo.
- -El loop de eventos
obtiene su nombre por la forma en que es usualmente implementado, la cual generalmente se parece a:
while(queue.waitForMessage()){ - queue.processNextMessage(); -}- -
queue.waitForMessage
espera de manera síncrona a que llegue un mensaje si no hay ninguno actualmente.
Cada mensaje es procesado completamente antes que cualquier otro mensaje sea procesado. Esto ofrece algunas propiedades convenientes al momento de pensar en un programa, incluido el hecho de que cada vez que una función se ejecuta, ésta no puede ser terminada y se ejecutará totalmente antes de que cualquier otro código se ejecute (y de este modo pueda modificar la información que la función manipula). Esto es diferente de C, por ejemplo, donde si una función se ejecuta en un hilo, esta puede ser detenida en cualquier punto para ejecutar código en otro hilo.
- -Una desventaja de este modelo es que, si un mensaje toma mucho tiempo en completarse, la aplicación es incapaz de procesar las interacciones de usuario, tales como clicks o scrolling. El navegador mitiga esta desventaja con el mensaje "un script esta tomando mucho tiempo en ejecutarse". Una buena práctica es hacer que el procesamiento del mensaje sea corto y, si es posible, dividir une mensaje en varios más.
- -En los navegadores web, los mensajes son añadidos cada vez que un evento ocurre y hay un escuchador de eventos asociado a él. Si no hay un escuchador, el evento se pierde. De este modo, al hacer click en un elemento con un manejador de eventos tipo click, se añadirá un mensaje. Lo mismo sucede en otros tipos de eventos.
- -Al llamar setTimeout
se añadirá un mensaje a la cola después de el tiempo especificado como segundo parámetro. Si no hay ningún otro mensaje en la cola, el mensaje es procesado en el momento; sin embargo, si hay mensajes en la cola, el mensaje de setTimeout
tendrá que esperar a que los otros mensajes sean procesados. Por esta razón el segundo parámetro indica el tiempo mínimo tiempo esperado y no es una garantía.
Cero retraso no significa que una llamada a una función (call back) se disparará después de cero milisegundos. Al llamar {{domxref("WindowTimers.setTimeout", "setTimeout")}} con un retraso de 0 (cero) milisegundos, no se ejecuta la llamada de la función después de el intervado dado. La ejecución depende del número de tareas en espera en la cola. En el ejemplo de abajo el mensaje "this is just a message" será escrito en la terminal antes de que el mensaje de la llamada a la función sea procesado, esto es por que el retraso es el tiempo mínimo requerido para que el programa procese la petición, pero no es un tiempo garantizado.
- -(function () { - - console.log('this is the start'); - - setTimeout(function cb() { - console.log('this is a msg from call back'); - }); - - console.log('this is just a message'); - - setTimeout(function cb1() { - console.log('this is a msg from call back1'); - }, 0); - - console.log('this is the end'); - -})(); - -// "this is the start" -// "this is just a message" -// "this is the end" -// cabe notar que la función retorna en este punto (undefined) -// "this is a msg from call back" -// "this is a msg from call back1" -- -
Un web worker o cross-origin iframe
tiene su propia pila, montículo y cola de mensajes. Dos programas diferentes solo se pueden comunicar enviando mensajes a través del método postMessage
. Este método añade un mensaje al otro programa si éste último escucha eventos de tipo message
.
Una propiedad muy interesante del modelo de loop de eventos es que JavaScript, a diferencia de otros lenguajes, nunca interrumpe otros programas en ejecución. Manejar operaciones de I/O (entrada/salida) es normalmente hecho a través de eventos y llamadas a función, de modo que cuando la aplicación, por ejemplo, está esperando por el retorno de una consulta IndexedDB o una petición XHR, ésta puede continuar procesando otras cosas como interacciones con el usuario (e.g. clicks).
- -Excepciones a esta regla existe en versiones anteriores del lenguaje, tales como alert
o XHR síncrono, pero es considerada una buena práctica evitar su uso. Finalmente, hay que estar conscientes que hay excepciones a las excepciones (pero son usualmente errores de implementación mas que otra cosa).
JavaScript provoca cierta confusión en desarrolladores con experiencia en lenguajes basados en clases (como Java o C++), por ser dinámico y no proporcionar una implementación de clases en sí mismo (la palabra clave class
se introdujo en ES2015, pero sólo para endulzar la sintaxis, ya que JavaScript sigue estando basado en prototipos).
En lo que a herencia se refiere, JavaScript sólo tiene una estructura: objetos. Cada objeto tiene una propiedad privada (referida como su [[Prototype]]) que mantiene un enlace a otro objeto llamado su prototipo. Ese objeto prototipo tiene su propio prototipo, y así sucesivamente hasta que se alcanza un objeto cuyo prototipo es null
. Por definición, null
no tiene prototipo, y actúa como el enlace final de esta cadena de prototipos.
Casi todos los objetos en JavaScript son instancias de {{jsxref("Object")}} que se sitúa a la cabeza de la cadena de prototipos.
- -A pesar de que a menudo esto se considera como una de las principales debilidades de JavaScript, el modelo de herencia de prototipos es de hecho más potente que el modelo clásico. Por ejemplo, es bastante simple construir un modelo clásico a partir de un modelo de prototipos.
- -Los objetos en JavaScript son "contenedores" dinámicos de propiedades (referidas como sus propiedades particulares). Los objetos en JavaScript poseen un enlace a un objeto prototipo. Cuando intentamos acceder a una propiedad de un objeto, la propiedad no sólo se busca en el propio objeto sino también en el prototipo del objeto, en el prototipo del prototipo, y así sucesivamente hasta que se encuentre una propiedad que coincida con el nombre o se alcance el final de la cadena de prototipos.
- -Siguiendo el estándar ECMAScript, la notación algunObjeto.[[Prototype]]
se usa para designar el prototipo de algunObjeto.
A partir de ECMAScript 2015, se accede al [[Prototype]]
utilizando los accesores {{jsxref("Object.getPrototypeOf()")}} y {{jsxref("Object.setPrototypeOf()")}}. Esto es equivalente a la propiedad JavaScript __proto__
que no es estándar pero es el de-facto implementado por los navegadores.
No debe confundirse con la propiedad de las funciones func.prototype
, que en cambio especifican el [[Prototype]]
a asignar a todas las instancias de los objetos creados por la función dada cuando se utiliza como un constructor. La propiedad Object.prototype
representa el prototipo del objeto {{jsxref("Object")}}.
Esto es lo que ocurre cuando intentamos acceder a una propiedad:
- -// Supongamos que tenemos un objeto
o, con propiedades a y b:
-// {a: 1, b: 2}
-// o.[[Prototype]] tiene propiedades b y c:
-// {b: 3, c: 4}
-// Finalmente, o.[[Prototype]].[[Prototype]] es null.
-// Este es el final de la cadena de prototipos, ya que null,
-// por definición, no tiene [[Prototype]].
-// Por tanto, la cadena completa de prototipos se vería como:
-// {a:1, b:2} ---> {b:3, c:4} ---> null
-
-console.log(o.a); // 1
-// ¿Hay una propiedad 'a' en o? Sí, y su valor es 1.
-
-console.log(o.b); // 2
-// ¿Hay una propiedad 'b' en o? Sí, y su valor es 2.
-// El prototipo también tiene una propiedad 'b', pero no se ha visitado.
-// Esto se llama "solapamiento de propiedades"
-
-console.log(o.c); // 4
-// ¿Hay una propiedad 'c' en o? No, comprobamos su prototipo.
-// ¿Hay una propiedad 'c' en o.[[Prototype]]? Sí, y su valor es 4.
-
-console.log(o.d); // undefined
-// ¿Hay una propiedad 'd' en o? No, comprobamos su prototipo.
-// ¿Hay una propiedad 'd' en o.[[Prototype]]? No, comprobamos su prototipo.
-// o.[[Prototype]].[[Prototype]] es null, paramos de buscar.
-// No se encontró la propiedad, se devuelve undefined
-
-
-Dar valor a una propiedad de un objeto crea una propiedad. La única excepción a las reglas de funcionamiento de obtener y dar valores ocurre cuando hay una propiedad heredada con un getter o un setter.
- -JavaScript no tiene "métodos" en la forma que los lenguajes basados en clases los define. En JavaScript, cualquier función puede añadirse a un objeto como una propiedad. Una función heredada se comporta como cualquier otra propiedad, viéndose afectada por el solapamiento de propiedades como se muestra anteriormente (siendo, en este caso, una especie de redefinición de métodos).
- -Cuando una función heredada se ejecuta, el valor de this
apunta al objeto que hereda, no al prototipo en el que la función es una propiedad.
var o = { - a: 2, - m: function(b){ - return this.a + 1; - } -}; - -console.log(o.m()); // 3 -// Cuando en este caso se llama a o.m, 'this' se refiere a o - -var p = Object.create(o); -// p es un objeto que hereda de o - -p.a = 12; // crea una propiedad 'a' en p -console.log(p.m()); // 13 -// cuando se llama a p.m, 'this' se refiere a p. -// De esta manera, cuando p hereda la función m de o, -// 'this.a' significa p.a, la propiedad 'a' de p -- -
Veamos lo que sucede detrás de escena detalladamente.
- -En JavaScript, como se mencionó anteriormente, las funciones pueden tener propiedades. Todas las funciones tienen una propiedad especial llamada prototype
. Por favor ten en cuenta que el siguiente código es autónomo (es seguro asumir que no hay otro JavaScript en la página web mas que el siguiente). Para la mejor experiencia de aprendizaje, es altamente recomendable que abras una consola (la cual, en Chrome y Firefox, se puede abrir presionando Ctrl+Shift+I), navegando hasta la pestaña "console", copiando y pegando el siguiente código JavaScript, y ejecutándolo presionando la tecla Enter/Return.
function hacerAlgo(){} -console.log( hacerAlgo.prototype ); -// No importa cómo declares la función, una -// función en JavaScript siempre tendrá una -// propiedad prototype predeterminada. -var hacerAlgo = function(){}; -console.log( hacerAlgo.prototype );- -
Como acabamos de ver, hacerAlgo()
tiene una propiedad prototype
predeterminada, como lo demuestra la consola. Después de ejecutar este código, la consola debería haber mostrado un parecido a esto.
{ - constructor: ƒ hacerAlgo(), - __proto__: { - constructor: ƒ Object(), - hasOwnProperty: ƒ hasOwnProperty(), - isPrototypeOf: ƒ isPrototypeOf(), - propertyIsEnumerable: ƒ propertyIsEnumerable(), - toLocaleString: ƒ toLocaleString(), - toString: ƒ toString(), - valueOf: ƒ valueOf() - } -}- -
Podemos añadir propiedades al prototipo de hacerAlgo()
, como se muestra a continuación.
function hacerAlgo(){} -hacerAlgo.prototype.foo = "bar"; -console.log( hacerAlgo.prototype );- -
El resultado:
- -{ - foo: "bar", - constructor: ƒ hacerAlgo(), - __proto__: { - constructor: ƒ Object(), - hasOwnProperty: ƒ hasOwnProperty(), - isPrototypeOf: ƒ isPrototypeOf(), - propertyIsEnumerable: ƒ propertyIsEnumerable(), - toLocaleString: ƒ toLocaleString(), - toString: ƒ toString(), - valueOf: ƒ valueOf() - } -}- -
Ahora podemos usar el operador new
para crear una instancia de hacerAlgo()
basado en este prototipo. Para usar el operador new
, llama la función normalmente pero añadiendo el prefijo new
. Llamar a la función con el operador new
devuelve un objeto que es una instancia de la función. Entonces las propiedades pueden ser añadidas a este objeto.
Intenta el siguiente código:
- -function hacerAlgo(){} -hacerAlgo.prototype.foo = "bar"; // añadir una propiedad al prototipo -var hacerUnaInstancia = new hacerAlgo(); -hacerUnaInstancia.prop = "un valor"; // añadir una propiedad al objeto -console.log( hacerUnaInstancia );- -
El resultado es similar a lo siguiente:
- -{ - prop: "un valor", - __proto__: { - foo: "bar", - constructor: ƒ hacerAlgo(), - __proto__: { - constructor: ƒ Object(), - hasOwnProperty: ƒ hasOwnProperty(), - isPrototypeOf: ƒ isPrototypeOf(), - propertyIsEnumerable: ƒ propertyIsEnumerable(), - toLocaleString: ƒ toLocaleString(), - toString: ƒ toString(), - valueOf: ƒ valueOf() - } - } -}- -
Como acabamos de ver, el __proto__
de hacerUnaInstancia
es hacerAlgo.prototype
. Pero, ¿qué hace esto? Cuando accedes a la propiedad de hacerUnaInstancia
, el navegador primero revisa si hacerUnaInstancia
tiene esa propiedad.
Si hacerUnaInstancia
no tiene la propiedad, entonces el navegador busca por la propiedad en el __proto__
de hacerUnaInstancia
(también conocido como hacerAlgo.prototype
). Si el __proto__
de hacerUnaInstancia
tiene la propiedad buscada, entonces la propiedad en el __proto__
de hacerUnaInstancia
es usada.
De otra manera, si el __proto__
de hacerUnaInstancia
no tiene la propiedad, entonces el __proto__
de __proto__
de hacerUnaInstancia
es revisado para la propiedad. Por defecto, el __proto__
de la propieda prototype
de cualquier función es window.Object.prototype
. Entonces, el __proto__
de el __proto__
de hacerUnaInstancia
(conocido como el __proto__
de hacerAlgo.prototype
(conocido como Object.prototype
)) es entonces revisado por la propiedad que se está buscando.
Si la propiedad no es encontrada en el __proto__
de el __proto__
de hacerUnaInstancia
, entonces el __proto__
de el __proto__
de el __proto__
de hacerUnaInstancia
es revisado. Sin embargo, hay un problema: el __proto__
de el __proto__
de el __proto__
de el __proto__
de hacerUnaInstancia
no existe. Entonces y sólo entonces, despues de que toda la cadena de prototipos de __proto__
's es revisada, y no haya mas __proto__
s el navegador afirma que la propiedad no existe y concluye que el valor de la propiedad es undefined
.
Vamos a intentar introduciendo más código en la consola:
- -function hacerAlgo(){} -hacerAlgo.prototype.foo = "bar"; -var hacerUnaInstancia = new hacerAlgo(); -hacerUnaInstancia.prop = "un valor"; -console.log("hacerUnaInstancia.prop: " + hacerUnaInstancia.prop); -console.log("hacerUnaInstancia.foo: " + hacerUnaInstancia.foo); -console.log("hacerAlgo.prop: " + hacerAlgo.prop); -console.log("hacerAlgo.foo: " + hacerAlgo.foo); -console.log("hacerAlgo.prototype.prop: " + hacerAlgo.prototype.prop); -console.log("hacerAlgo.prototype.foo: " + hacerAlgo.prototype.foo);- -
El resultado es el siguiente:
- -hacerUnaInstancia.prop: un valor -hacerUnaInstancia.foo: bar -hacerAlgo.prop: undefined -hacerAlgo.foo: undefined -hacerAlgo.prototype.prop: undefined -hacerAlgo.prototype.foo: bar- -
var o = {a: 1}; - -// El objeto recién creado o tiene Object.prototype como su [[Prototype]] -// o no tiene ninguna propiedad llamada 'hasOwnProperty' -// hasOwnProperty es una propiedad propia de Object.prototype. -// Entonces o hereda hasOwnProperty de Object.prototype -// Object.prototype es null como su prototype. -// o ---> Object.prototype ---> null - -var a = ["yo", "whadup", "?"]; - -// Arrays hereda de Array.prototype -// (que tiene métodos como indexOf, forEach, etc.) -// La cadena de prototipados sería: -// a ---> Array.prototype ---> Object.prototype ---> null - -function f(){ - return 2; -} - -// Las funciones heredan de Function.prototype -// (que tiene métodos como call, bind, etc.) -// f ---> Function.prototype ---> Object.prototype ---> null -- -
Un "constructor" en JavaScript es "solo" una función que pasa a ser llamada con el operador new.
- -function Graph() { - this.vertices = []; - this.edges = []; -} - -Graph.prototype = { - addVertex: function(v){ - this.vertices.push(v); - } -}; - -var g = new Graph(); -// g es un objeto con las propiedades 'vértices' y 'edges'. -// g.[[Prototype]] es el valor de Graph.prototype cuando new Graph() es ejecutado. -- -
Object.create
ECMAScript 5 Introdujo un nuevo método: {{jsxref("Object.create()")}}. Llamando este método creas un nuevo objeto. El prototype de este objeto es el primer argumento de la función:
- -var a = {a: 1}; -// a ---> Object.prototype ---> null - -var b = Object.create(a); -// b ---> a ---> Object.prototype ---> null -console.log(b.a); // 1 (heredado) - -var c = Object.create(b); -// c ---> b ---> a ---> Object.prototype ---> null - -var d = Object.create(null); -// d ---> null -console.log(d.hasOwnProperty); -// undefined, por que d no hereda de Object.prototype -- -
class
ECMAScript 2015 introduce un nuevo set de palabras reservadas que implementan clases. Aunque estos constructores lucen más familiares para los desarrolladores de lenguajes basados en clases, aun así no son clases. JavaScript sigue estando basado en prototipos. Los nuevos keywords incluyen {{jsxref("Statements/class", "class")}}, {{jsxref("Classes/constructor", "constructor")}}, {{jsxref("Classes/static", "static")}}, {{jsxref("Classes/extends", "extends")}}, and {{jsxref("Operators/super", "super")}}.
- -"use strict"; - -class Polygon { - constructor(height, width) { - this.height = height; - this.width = width; - } -} - -class Square extends Polygon { - constructor(sideLength) { - super(sideLength, sideLength); - } - get area() { - return this.height * this.width; - } - set sideLength(newLength) { - this.height = newLength; - this.width = newLength; - } -} - -var square = new Square(2); -- -
El tiempo de búsqueda para las propiedades que están en lo alto de la cadena de prototipo puede tener un impacto negativo en el rendimiento, y esto puede ser significativo en el código donde el rendimiento es crítico. Además, tratar de acceder a las propiedades inexistentes siempre atravesara la cadena de prototipos completamente.
- -También, cuando iteramos sobre las propiedades de un objeto, cada propiedad enumerable que se encuentra en la cadena de prototipo será enumerada.
- -Para comprobar si un objeto tiene una propiedad definida en sí mismo y no en alguna parte de su cadena de prototipo, Es necesario usar para esto el método hasOwnProperty
que todos los objetos heredan de Object.prototype
.
hasOwnProperty
es la única cosa en JavaScript que se ocupa de las propiedades y no atraviesa la cadena de prototipos.
Nota: Esto no es suficiente para chequear si una propiedad esta undefined
. la propiedad podría existir, pero el valor justamente sucede que esta seteado como undefined
.
Una mala característica que a menudo se usa, es extender Object.prototype
o uno de los otros pre-incorporados prototypes.
Esta técnica se llama monkey patching y rompe la encapsulación. Si bien, es utilizado por librerías como Prototype.js, no hay una buena razón para saturar los tipos pre-incorporados con funcionalidades adicionales no estándar.
- -La única buena razón para extender los pre-incorporados prototipos es modificar las funcionalidades nuevas de los motores de JavaScript; por ejemplo:
- -Array.forEach
, etc.
B
heredará de A
:
function A(a){ - this.varA = a; -} - -// Cual es el propósito de incluir varA en el prototipo si A.prototype.varA siempre va a ser la sombra de -// this.varA, dada la definición de la función A arriba? -A.prototype = { - varA : null, // No deberíamos atacar varA desde el prototipo como haciendo nada? - // Tal vez intentando una optimización al asignar espacios ocultos en las clases? - // https://developers.google.com/speed/articles/optimizing-javascript#Initializing instanciar variables - // podría ser válido si varA no fuera inicializado únicamente por cada instancia. - doSomething : function(){ - // ... - } -} - -function B(a, b){ - A.call(this, a); - this.varB = b; -} -B.prototype = Object.create(A.prototype, { - varB : { - value: null, - enumerable: true, - configurable: true, - writable: true - }, - doSomething : { - value: function(){ // override - A.prototype.doSomething.apply(this, arguments); // call super - // ... - }, - enumerable: true, - configurable: true, - writable: true - } -}); -B.prototype.constructor = B; - -var b = new B(); -b.doSomething(); -- -
Las partes importantes son:
- -.prototype
Object.create()
para heredarprototype
y Object.getPrototypeOf
JavaScript es un poco confuso para desarrolladores que vienen de lenguajes como Java o C++, ya que todo es dinámico, en todo momento de la ejecución, y no tiene clases en lo absoluto. Todo es solamente instancias (objetos). Incluso las "clases" que creamos, son solo funciones (objetos).
- -Probablemente notaste que nuestra función A
tiene una propiedad especial llamada prototype
. Esta propiedad especial funciona con el operador de JavaScript new
. La referencia al prototipo objeto es copiada al interno [[Prototype]]
propiedad de la instancia new. Por ejemplo, cuando creas una variable var a1 = new A()
, JavaScript (después de haber creado el objeto en memoria y antes de correr function A()
con this
definido a él) setea a1.[[Prototype]] = A.prototype
. Cuando a continuación accedes a las propiedades de la instancia, JavaScript primero chequea si existen en el objeto directamente, y si no, mira en el [[Prototype]]
. Esto significa que todo lo que definas en el prototipo
es efectivamente compartido a todas las instancias, e incluso después puedes cambiar partes del prototipo
y que todos los cambios se hagan en todas las instancias.
Si, en el ejemplo de arriba, pones var a1 = new A(); var a2 = new A();
entonces a1.doSomething
se referiría a Object.getPrototypeOf(a1).doSomething
, que seria lo mismo que A.prototype.doSomething
que definiste, i.e. Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething
.
resumiendo, prototype
es para tipos, mientras que Object.getPrototypeOf()
es lo mismo para instancias.
[[Prototype]]
es visto como recursivo, i.e. a1.doSomething
, Object.getPrototypeOf(a1).doSomething
, Object.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething
etc., hasta que se encuentra o Object.getPrototypeOf
retornará null.
Entonces, cuando llamas
- -var o = new Foo();- -
JavaScript en realidad hace
- -var o = new Object(); -o.[[Prototype]] = Foo.prototype; -Foo.call(o);- -
(o algo similar) y cuando después haces
- -o.someProp;- -
chequea si o
tiene una propiedad someProp
. Si no, busca en Object.getPrototypeOf(o).someProp
y si ahí no existe, busca en Object.getPrototypeOf(Object.getPrototypeOf(o)).someProp
y así sucesivamente.
Es esencial entender el modelo de prototipado por instancias antes de escribir código complejo que hace uso de esto. También, sé consciente del largo de la cadena de prototipado en tu código y romperlo si es necesario para evitar posibles problemas de rendimiento. Adicionalmente, el prototipo nativo nunca debería ser extendido a menos que esto sea por motivo de compatibilidad con nuevas versiones de JavaScript.
-Mientras que HTML define la estructura y el contenido de una página web y el CSS define el formato y la apariencia, JavaScript agrega interactividad a una página web y crea aplicaciones web enriquecidas.
- -Sin embargo, el término paraguas "JavaScript", tal como se entiende en un contexto de navegador web, contiene varios elementos muy diferentes. Uno de ellos es el lenguaje principal (ECMAScript), otro es la colección de las APIs Web, incluyendo el DOM (Document Object Model).
- -EL núcleo del lenguaje JavaScript está estandarizado por el Comité ECMA TC39 como un lenguaje llamado ECMAScript. La última versión de la especificación es ECMAScript 6.0.
- -Éste núcleo del lenguaje es también usado en ambientes No-Navegadores, por ejemplo en node.js.
- -Entre otras cosas, ECMAScript define:
- -parseInt
, parseFloat
, decodeURI
, encodeURI
...JSON
, Math
, Array.prototype
methods, Object introspection methods...)A partir de Octubre del 2016, la gran mayoria de los navegadores soportan ECMAScript 5.1 y ECMAScript 2015 aka ES6, pero versiones antiguas (aún en uso) implementan ECMAScript 5 solamente.
- -La 6ta edición principal de ECMAScript fue oficialmente aprobada y publicada como un estándar el 17 de Junio del 2015 por la ECMA General Assembly. Desde entonces las ediciones de ECMAScript son publicadas anualmente.
- -La ECMAScript Internationalization API Specification es una adición para la especificación del lenguaje ECMAScript, también estandarizada por Ecma TC39. La internacionalización de la API provee intercalación --collation-- (comparación de string), formateo de números, y fomateo de fechas/tiempo para aplicaciones JavaScript, permitiendo que las aplicaciones elijan el idioma y adapten la funcionalidad a sus necesidades. El estandar inicial fue aprobado en Diciembre del 2012; el estado de la implementación en navegadores es rastreado en la documentación de la Intl
object. Las especificaciones de la internacionalización son actualmente ratificadas cada año y los navegadores constantemente mejoran su implementación.
Las especificaciones de la WebIDL proporcionan el vínculo de las tecnologías DOM y ECMAScript.
- -El Document Object Model (DOM) es una convención multiplataforma e independiente del lenguaje para representar e interactuar con objetos en documentos HTML, XHTML y XML. Los objetos en el árbol DOM se pueden abordar y manipular mediante el uso de métodos en los objetos de otras tecnologías. El {{Glossary("W3C")}} estandariza el Modelo de Objetos del Documento Central, que define interfaces independientes del lenguaje que abstraen documentos HTML y XML como objetos, y también define mecanismos para manipular esta abstracción. Entre las cosas definidas por el DOM, podemos encontrar:
- -Node
, Element
, DocumentFragment
, Document
, DOMImplementation
, Event
, EventTarget
, …Desde el punto de vista ECMAScript, los objetos definidos en la especificación DOM se denominan "objetos host".
- -HTML, el lenguaje de marcado de la Web, se especifica en términos del DOM. Por encima de los conceptos abstractos definidos en DOM Core, HTML también define el significado de los elementos. El DOM HTML incluye cosas como el className
propiedad en elementos HTML o API como {{domxref ("document.body")}}.
La especificación HTML también define restricciones en los documentos; por ejemplo, requiere que todos los elementos secundarios de un elemento ul
que representa una lista desordenada, sean elementos li
, ya que representan elementos de la lista. En general, también prohíbe el uso de elementos y atributos que no están definidos en un estándar.
¿Busca Document
object, Window
object, y los otros elementos DOM? ? Lee la documentación DOM documentation.
setTimeout
y setInterval
se especificaron por primera vez en la interfaz de Window
en HTML Standard.Como todos los desarrolladores web han experimentado, el DOM es un desastre. La uniformidad del soporte del navegador varía mucho de una característica a otra, principalmente porque muchas características DOM importantes tienen especificaciones muy poco claras (si las hay), y diferentes navegadores web agregan características incompatibles para casos de uso superpuestos (como el modelo de evento de Internet Explorer). A partir de junio de 2011, el W3C y particularmente el WHATWG están definiendo características antiguas en detalle para mejorar la interoperabilidad, y los navegadores a su vez pueden mejorar sus implementaciones basadas en estas especificaciones.
- -Un enfoque común, aunque quizás no el más confiable, para la compatibilidad entre navegadores es usar bibliotecas de JavaScript, que resumen las funciones DOM y mantienen sus API funcionando igual en diferentes navegadores. Algunos de los frameworks más utilizados son jQuery, prototype, y YUI.
diff --git a/files/es/web/javascript/javascript_technologies_overview/index.md b/files/es/web/javascript/javascript_technologies_overview/index.md new file mode 100644 index 00000000000000..73ea244c7e26a5 --- /dev/null +++ b/files/es/web/javascript/javascript_technologies_overview/index.md @@ -0,0 +1,82 @@ +--- +title: Descripción de las tecnologías JavaScript +slug: Web/JavaScript/JavaScript_technologies_overview +translation_of: Web/JavaScript/JavaScript_technologies_overview +original_slug: Web/JavaScript/Descripción_de_las_tecnologías_JavaScript +--- +{{JsSidebar("Introductory")}} + +## Introducción + +Mientras que HTML define la estructura y el contenido de una página web y el CSS define el formato y la apariencia, JavaScript agrega interactividad a una página web y crea aplicaciones web enriquecidas. + +Sin embargo, el término paraguas "JavaScript", tal como se entiende en un contexto de navegador web, contiene varios elementos muy diferentes. Uno de ellos es el lenguaje principal (ECMAScript), otro es la colección de las APIs Web, incluyendo el DOM (Document Object Model). + +## JavaScript, el núcleo del lenguaje (ECMAScript) + +EL núcleo del lenguaje JavaScript está estandarizado por el Comité ECMA TC39 como un lenguaje llamado [ECMAScript](/es/docs/JavaScript/Language_Resources). La última versión de la especificación es [ECMAScript 6.0](http://www.ecma-international.org/ecma-262/6.0/). + +Éste núcleo del lenguaje es también usado en ambientes No-Navegadores, por ejemplo en [node.js](http://nodejs.org/). + +### Qué considera ECMAScript scope? + +Entre otras cosas, ECMAScript define: + +- Sintaxis (reglas de análisis, palabras clave, flujos de control, inicialización literal de objetos...). +- Mecanismos de control de errores (throw, try/catch, habilidad para crear tipos de Errores definidos por el usuario). +- Tipos (boolean, number, string, function, object...). +- Los objetos globales. En un navegador, estos objetos globales son los objetos de la ventana, pero ECMAScript solo define APIs no especificas para navegadores, ej. `parseInt`, `parseFloat`, `decodeURI`, `encodeURI`... +- Mecanismo de herencia basada en prototipos. +- Objetos y funciones incorporadas (`JSON`, `Math`, `Array.prototype` methods, Object introspection methods...) +- Modo estricto. + +### Navegadores soportados + +A partir de Octubre del 2016, la gran mayoria de los navegadores soportan [ECMAScript 5.1](/es/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_5_support_in_Mozilla) y [ECMAScript 2015 aka ES6](/es/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla), pero versiones antiguas (aún en uso) implementan ECMAScript 5 solamente. + +### Futuro + +La 6ta edición principal de ECMAScript fue oficialmente aprobada y publicada como un estándar el 17 de Junio del 2015 por la ECMA General Assembly. Desde entonces las ediciones de ECMAScript son publicadas anualmente. + +### Internacionalización de la API + +La [ECMAScript Internationalization API Specification](http://ecma-international.org/ecma-402/1.0/) es una adición para la especificación del lenguaje ECMAScript, también estandarizada por Ecma TC39. La internacionalización de la API provee intercalación --collation-- (comparación de string), formateo de números, y fomateo de fechas/tiempo para aplicaciones JavaScript, permitiendo que las aplicaciones elijan el idioma y adapten la funcionalidad a sus necesidades. El estandar inicial fue aprobado en Diciembre del 2012; el estado de la implementación en navegadores es rastreado en la documentación de la [`Intl` object](/es/docs/JavaScript/Reference/Global_Objects/Intl). Las especificaciones de la internacionalización son actualmente ratificadas cada año y los navegadores constantemente mejoran su implementación. + +## DOM APIs + +### WebIDL + +Las especificaciones de la [WebIDL](http://www.w3.org/TR/WebIDL/) proporcionan el vínculo de las tecnologías DOM y ECMAScript. + +### El núcleo del DOM + +El Document Object Model (DOM) es una **convención multiplataforma e independiente** del lenguaje para representar e interactuar con objetos en documentos HTML, XHTML y XML. Los objetos en el **árbol DOM** se pueden abordar y manipular mediante el uso de métodos en los objetos de otras tecnologías. El {{Glossary("W3C")}} estandariza el Modelo de Objetos del Documento Central, que define interfaces independientes del lenguaje que abstraen documentos HTML y XML como objetos, y también define mecanismos para manipular esta abstracción. Entre las cosas definidas por el DOM, podemos encontrar: + +- La estructura del documento, un modelo de árbol, y la arquitectura de eventos DOM en el nucleo del DOM: `Node`, `Element`, `DocumentFragment`, `Document`, `DOMImplementation`, `Event`, `EventTarget`, … +- Una definición menos rigurosa de la arquitectura de eventos DOM, así como eventos específicos en eventos DOM. +- Otras cosas como DOM Traversal y el DOM Range. + +Desde el punto de vista ECMAScript, los objetos definidos en la especificación DOM se denominan "objetos host". + +### HTML DOM + +HTML, el lenguaje de marcado de la Web, se especifica en términos del DOM. Por encima de los conceptos abstractos definidos en DOM Core, HTML también define el significado de los elementos. El DOM HTML incluye cosas como el `className` propiedad en elementos HTML o API como {{domxref ("document.body")}}. + +La especificación HTML también define restricciones en los documentos; por ejemplo, requiere que todos los elementos secundarios de un elemento `ul` que representa una lista desordenada, sean elementos `li`, ya que representan elementos de la lista. En general, también prohíbe el uso de elementos y atributos que no están definidos en un estándar. + +¿Busca [`Document` object](/es/docs/DOM/document), [`Window` object](/es/docs/DOM/window), y los otros elementos DOM? ? Lee la documentación [DOM documentation](/es/docs/Web/API/Document_Object_Model). + +## Otras API notables + +- Las funciones `setTimeout` `ysetInterval` se especificaron por primera vez en la interfaz de [`Window`](http://www.whatwg.org/html/#window) en HTML Standard. +- [XMLHttpRequest](https://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html) hace posible enviar solicitudes HTTP asincrónicas. +- EL [Modelo de Objetos CSS](http://dev.w3.org/csswg/cssom/) esume las reglas CSS como objetos. +- [WebWorkers ](http://www.whatwg.org/specs/web-workers/current-work/)permite el cálculo paralelo. +- [WebSockets](http://www.whatwg.org/C/#network) permite la comunicación bidireccional de bajo nivel. +- [Canvas 2D Context](http://www.whatwg.org/html/#2dcontext) es una API de dibujo para {{htmlelement("canvas")}}. + +### Soporte del navegador + +Como todos los desarrolladores web han experimentado, [el DOM es un desastre](http://ejohn.org/blog/the-dom-is-a-mess/). La uniformidad del soporte del navegador varía mucho de una característica a otra, principalmente porque muchas características DOM importantes tienen especificaciones muy poco claras (si las hay), y diferentes navegadores web agregan características incompatibles para casos de uso superpuestos (como el modelo de evento de Internet Explorer). A partir de junio de 2011, el W3C y particularmente el WHATWG están definiendo características antiguas en detalle para mejorar la interoperabilidad, y los navegadores a su vez pueden mejorar sus implementaciones basadas en estas especificaciones. + +Un enfoque común, aunque quizás no el más confiable, para la compatibilidad entre navegadores es usar bibliotecas de JavaScript, que resumen las funciones DOM y mantienen sus API funcionando igual en diferentes navegadores. Algunos de los frameworks más utilizados son [jQuery](http://jquery.com/), [prototype](http://www.prototypejs.org/), y [YUI](http://developer.yahoo.com/yui/). diff --git a/files/es/web/javascript/memory_management/index.html b/files/es/web/javascript/memory_management/index.html deleted file mode 100644 index bc58509017161e..00000000000000 --- a/files/es/web/javascript/memory_management/index.html +++ /dev/null @@ -1,205 +0,0 @@ ---- -title: Gestión de Memoria -slug: Web/JavaScript/Memory_Management -tags: - - Advanced - - JavaScript - - Performance - - Reference - - Referencia - - Rendimiento - - memoria -translation_of: Web/JavaScript/Memory_Management -original_slug: Web/JavaScript/Gestion_de_Memoria ---- -Los lenguajes de bajo nivel, como C, tienen primitivos de bajo nivel como malloc()
y free()
para la gestión de memoria. Por otro lado, para los valores en JavaScript se reserva memoria cuando"cosas" (objetos, strings, etc.) son creados y "automáticamente" liberados cuando ya no son utilizados. El proceso anterior es conocido como Recolección de basura (garbage collection). Su forma "automática" es fuente de confusión, y da la impresión a los desarrolladores de JavaScript (y de otros lenguajes de alto nivel) de poder ignorar el proceso de gestión de memoria. Esto es erróneo.
Sin importar el lenguaje de programación, el ciclo de memoria es casi siempre parecido al siguiente:
- -El primer y el segundo paso son explícitos en todos los lenguajes. El último paso es explícito en lenguajes de bajo nivel, pero es mayormente implícito en lenguajes de alto nivel como JavaScript
- -Para no agobiar al programador con reservas de memoria, JavaScript las realiza al mismo tiempo que la declaración de los valores.
- -var n = 123; // reserva memoria para un número -var s = "azerty"; // reserva memoria para un string - -var o = { - a: 1, - b: null -}; // reserva memoria para un objeto y los valores que - // contiene - -// (similar a objeto) reserva memoria para el arreglo y -// los valores que contiene -var a = [1, null, "abra"]; - -function f(a){ - return a + 2; -} // reserva memoria para una funcion (la cual es un objeto) - -// las expresiones de función tambien reservan memoria para un objeto -someElement.addEventListener('click', function(){ - someElement.style.backgroundColor = 'blue'; -}, false); -- -
En ocasiones al llamar a una función se reserva memoria para un objeto.
- -var d = new Date(); -// reserva memoria para un elemento del DOM -var e = document.createElement('div'); -- -
Algunos métodos reservan memoria para nuevos valores u objetos:
- -var s = "azerty"; -var s2 = s.substr(0, 3); // s2 es un nuevo string -// Como los strings son valores inmutables, -// JavaScript puede NO reservar memoria para este, -// y solo almacenar el rango [0, 3]. - -var a = ["ouais ouais", "nan nan"]; -var a2 = ["generation", "nan nan"]; -var a3 = a.concat(a2); -// nuevo arreglo con 4 elementos resultado de -// concatenar los elementos de a y a2 -- -
Usar un valor es simplemente leerlo o escribirlo en memoria reservada. Esto puede ocurrir al leer o escribir el valor de una variable o de una propiedad de un objeto, inclusive pasando un argumento a una función.
- -En este punto ocurren la mayoria de los inconvenientes con la gestión de memoria. Lo más díficil es encontrar el cuándo la "memoria ya no es necesaria". En algunas ocasiones, es necesario que el desarrollador determine en qué parte de un programa esa parte de memoria ya no es necesaria y la libere.
- -Los lenguajes de alto nivel incluyen una herramienta de software conocida como "recolector de basura" (garbage collector), cuya función es rastrear las reservas de memoria y su utilización, para así encontrar cuándo cierta parte de la memoria ya no es necesaria, y en su momento liberarla automáticamente. Este proceso es sólo una aproximación al problema general de saber cuándo una parte de la memoria ya no es necesaria, ya que éste es indecidible (no puede ser resuelto por un algoritmo).
- -Como antes se mencionaba el problema general de encontrar automáticamente cuando la memoria "ya no es necesaria" es indecidible. Como consecuencia, las recolecciones de basura implementan sólo una restricción a la solución del problema general. En esta sección se explicarán las nociones necesarias para entender los principales algoritmos de recolección de basura y sus limitaciones.
- -La noción principal de los algoritmos de recolección se basan en la noción de referencia. Dentro del contexto de gestión de memoria, se dice que un objeto hace referencia a otro si el primero tiene acceso al segundo (ya sea de forma implícita o explícita). Por ejemplo, un objeto de JavaScript guarda una referencia a su prototipo (referencia implícita) y a cualquiera de los valores de sus propiedades (referencia explícita)
- -Hay que mencionar que en este contexto la noción de "objeto" se refiere a algo más amplio que los objetos normales de JavaScript y que también incluye al ámbito de la función (o ámbito de léxico global).
- -Éste es el algoritmo de recolección más simple. Este algoritmo reduce la definición de "un objejo ya no es necesario" a "un objeto ya no tiene ningún otro objeto que lo referencíe". Un objeto es considerado recolectable si existen cero referencias hacia él.
- -var o = { - a: { - b:2 - } -}; -// Se crean dos objetos. Uno es referenciado por el otro como -// una de sus propiedades. -// El otro es referenciado al ser asignado a la variable "o" -// Ninguno puede ser recolectado. - - -var o2 = o; // la variable "o2" es lo segundo en tener una - // referencia al objeto. -o = 1; // ahora el objeto solo tiene una referencia mediante - // la variable "o2" - -var oa = o2.a; // referencia a la propiedad "a" del objeto. - // ahora el objeto posee dos referencias, una como propiedad - // la otra como la variable "oa" - -o2 = "yo"; // el objeto original "o" ahora ya no tiene - // referencias a él. Podría ser recolectado. - // Sin embargo lo que había en la propiedad "a" aún - // esta refernciado en la variable "oa"; - // no puede ser recolectado aún - -oa = null; // lo que estaba en la propiedad "a" del objeto original "o" - // ahora ya no tiene ninguna referencia.Puede ser recolectado. -- -
Existe una limitación cuando se trata de ciclos. En el siguiente ejemplo dos objetos son creados y se referencían entre ellos -por lo que se crea un ciclo. Ellos no saldrán del ámbito de la función después del llamado de la función, con lo que serían efectivamente "ya no son necesarios" y por lo cual ser liberados. Sin embargo, el algoritmo de conteo de referencias considera que ya que cada uno de los dos objetos está referenciado por lo menos una vez, ninguno podra ser recolectado. Este simple algoritmo tiene la limitación de que si un grupo de objetos se referencian a sí mismos (y forman un ciclo), nunca pasarán a "ya no ser necesitados" y no podrán ser recolectados nunca.
- -function f(){ - var o = {}; - var o2 = {}; - o.a = o2; // o referencía o2 - o2.a = o; // o2 referencía o - - return "azerty"; -} - -f(); -// Dos objetos son creados y se referencían uno al otro creando un ciclo -// Estan atrapados en el scope de la funcion después de la llamada -// por lo que son inútiles fuera de la función y podrían ser recolectados. -// Sin embargo, el algoritmo de conteo de referencias considera que como -// ambos objetos estan referenciados (aunque sean a si mismos) ambos -// siguen en uso y por lo tanto no pueden ser recolectados. - -- -
Internet Explorer 6 y 7 son conocidos por tener recolectores de basura por conteo de referencias para los objetos del DOM. Los Ciclos son un error común que pueden generar fugas de memoria (memory leaks) (art. en inglés):
- -var div;
-window.onload = function(){
- div = document.getElementById("miDiv");
- div.referenciaCircular = div;
- div.muchosDatos = new Array(10000).join("*");
-};
-
-
-En el ejemplo anterior, el elemento del DOM "miDiv" posée una referencia circular a sí mismo en la propiedad "referenciaCircular". Si la propiedad no es explícitamente removida o asignada con el valor null, un algoritmo de conteo de referencias siempre va a dejar por lo menos una referencia intacta y va a mantener el elemento del DOM activo en memoria incluso cuando es removido del DOM. Si el objeto del DOM contiene una gran cantidad de datos (ejemplificado en la propiedad "muchosDatos"), la memoria consumida por estos datos nunca será liberada.
- -Este algoritmo reduce la definición de "un objeto ya no es necesitado" a "un objeto es inalcanzable"
- -Este algoritmo asume la noción de un grupo de objetos llamados objetos raíz (en JavaScript la raíz es el objeto global). Periódicamente el recolector empieza por estas raíces, encuentra todos los objetos que están referenciados por estas raíces, y luego todos los objetos referenciados de estos, etc. Empezando por las raíces, el recolector de esta forma encontrará todos los objetos que son alcanzables y recolectará los objetos inalcanzables.
- -Este algoritmo es mejor que el anterior ya que "un objeto tiene cero referencias" equivale al "objeto es inalcanzable". Esto no sucedía asi en el algoritmo anterior cuando se trataba de un ciclo.
- -Desde el 2012, todos los navegadores incluyen un recolector de basura basado en mark-and-sweep. Todas las mejoras realizadas en el campo de Recolección de basura en JavaScript (recolección generacional/incremental/concurrida/paralela) en los ultimos años son mejoras a la implementación del algoritmo, pero no mejoras sobre el algoritmo de recolección ni a la reducción de la definicion de cuando"un objeto ya no es necesario".
- -En el primer ejemplo, después de que la llamada a una función termina, los dos objetos ya no son referenciados por nada alcanzable desde el objeto global. De esta forma serán identificados como inalcanzables por el recolector de basura.
- -Lo mismo ocurre en el segundo ejemplo. Una vez que el elemento div y sus métodos se hacen inalcanzable desde los objetos raíz, ambos pueden ser recolectados a pesar de que estén referenciados los unos de los otros.
- -Aunque esto está marcado como una limitación, se puede encontrar muy poco en la práctica. Ésta es la razón por la cuál la recolección de basura es poco tomada en cuenta.
- -Los arreglos tipados en JavaScript son objetos similares a arreglos que proporcionan un mecanismo para leer y escribir datos binarios sin procesar en búferes de memoria. Como ya sabrás, los objetos {{jsxref("Array", "Arreglo")}} crecen y se encogen dinámicamente y pueden tener cualquier valor de JavaScript. Los motores de JavaScript realizan optimizaciones para que estos arreglos sean rápidos.
- -Sin embargo, a medida que las aplicaciones web se vuelven cada vez más poderosas, agregando características como manipulación de audio y video, acceso a datos sin procesar usando WebSockets
, etc., ha quedado claro que hay momentos en los que sería útil que el código JavaScript pudiera manipular rápida y fácilmente datos binarios sin procesar. Aquí es donde entran en juego los arreglos tipados. Cada entrada en un arreglo tipado de JavaScript es un valor binario sin procesar en uno de los formatos admitidos, desde números enteros de 8 bits hasta números de punto flotante de 64 bits.
Sin embargo, los arreglos tipados no se deben confundir con los arreglos normales, ya que llamar a {{JSxRef("Array.isArray()")}} en un arreglo tipado devuelve false
. Además, no todos los métodos disponibles para arreglos normales son compatibles con arreglos tipados (por ejemplo, push
y pop
).
Para lograr la máxima flexibilidad y eficiencia, los arreglos de JavaScript dividen la implementación en búferes y vistas. Un búfer (implementado por el objeto {{jsxref("ArrayBuffer")}} es un objeto que representa una porción de datos; no tiene ningún formato del que hablar y no ofrece ningún mecanismo para acceder a su contenido. Para acceder a la memoria contenida en un búfer, necesitas usar una vista. Una vista proporciona un contexto — es decir, un tipo de dato, un desplazamiento inicial y el número de elementos — que convierte los datos en un arreglo tipado.
- - - -ArrayBuffer
{{jsxref("ArrayBuffer")}} es un tipo de dato que se utiliza para representar un búfer de datos binarios genérico de longitud fija. No puedes manipular directamente el contenido de un ArrayBuffer
; en su lugar, crea una vista de arreglo tipado o un {{JSxRef("DataView")}} que representa el búfer en un formato específico, y lo usa para leer y escribir el contenido del búfer.
Las vistas de arreglos tipados tienen nombres autodescriptivos y proporcionan vistas para todos los tipos numéricos habituales tal como Int8
, Uint32
, Float64
y así sucesivamente. Hay una vista de arreglo tipado especial, la Uint8ClampedArray
. Esta fija los valores entre 0 y 255. {{JSxRef("../Data_structures", "Tipos de datos JavaScript")}}
Tipo | -Intervalo de valores | -Tamaño en bytes | -Descripción | -Tipo de IDL web | -Tipo C equivalente | -
---|---|---|---|---|---|
{{JSxRef("Int8Array")}} | --128 a 127 |
- 1 | -Dos enteros complementarios de 8 bits con signo | -byte |
- int8_t |
-
{{JSxRef("Uint8Array")}} | -0 a 255 |
- 1 | -Entero de 8-bit sin signo | -octet |
- uint8_t |
-
{{JSxRef("Uint8ClampedArray")}} | -0 a 255 |
- 1 | -Entero de 8 bits sin signo (sujeto) | -octet |
- uint8_t |
-
{{JSxRef("Int16Array")}} | --32768 a 32767 |
- 2 | -Dos enteros complementarios de 16 bits con signo | -short |
- int16_t |
-
{{JSxRef("Uint16Array")}} | -0 a 65535 |
- 2 | -Entero de 16 bits sin signo | -Short sin signo |
- uint16_t |
-
{{JSxRef("Int32Array")}} | --2147483648 a 2147483647 |
- 4 | -dos enteros complementarios de 32 bits con signo | -long |
- int32_t |
-
{{JSxRef("Uint32Array")}} | -0 a 4294967295 |
- 4 | -Enteros de 32 bits sin signo | -long sin signo |
- uint32_t |
-
{{JSxRef("Float32Array")}} | -1.2 ×10-38 a 3.4 ×1038 |
- 4 | -Número de coma flotante IEEE de 32 bits (7 dígitos significativos, p. ej., 1.1234567 ) |
- float sin restricciones |
- float |
-
{{JSxRef("Float64Array")}} | -1.2 ×10-38 a 3.4 ×10308 |
- 8 | -Número de coma flotante IEEE de 64 bits (16 dígitos significativos, p. ej., 1.123...15 ) |
- doble sin restricciones |
- double |
-
{{JSxRef("BigInt64Array")}} | --263 a 263-1 |
- 8 | -Dos enteros complementarios de 64 bits con signo | -bigint |
- int64_t (long long con signo) |
-
{{JSxRef("BigUint64Array")}} | -0 a 264-1 |
- 8 | -Entero de 64 bits sin signo | -bigint |
- uint64_t (long long sin signo) |
-
DataView
{{jsxref("DataView")}} es una interfaz de bajo nivel que proporciona una API captadora (getter
)/(setter
) establecedora para leer y escribir datos arbitrarios en el búfer. Esto es útil cuando se trata de diferentes tipos de datos, por ejemplo. Las vistas de arreglos tipados están en el orden de bytes nativo (consulta {{Glossary("Endianness")}} de tu plataforma. Con un DataView
puedes controlar el orden de bytes. Es big-endian
de manera predeterminada y se puede establecer en little-endian
en los métodos captadores/establecedores.
Estos son algunos ejemplos de APIs que utilizan arreglos tipados; hay otras, y todo el tiempo surgen más.
- -FileReader.prototype.readAsArrayBuffer()
comienza a leer el contenido del Blob o File.XMLHttpRequest.prototype.send()
send()
de instancias de XMLHttpRequest
ahora admiten arreglos tipados y objetos {{JSxRef("ArrayBuffer")}} como argumento.0
y 255
inclusive.En primer lugar, necesitaremos crear un búfer, aquí con una longitud fija de 16 bytes:
- -let buffer = new ArrayBuffer(16); -- -
En este punto, tenemos una porción de memoria cuyos bytes están todos preiniciados a 0. Sin embargo, no hay mucho que podamos hacer con él. Podemos confirmar que de hecho tiene 16 bytes de longitud, y eso es todo:
- -if (buffer.byteLength === 16) { - console.log("Sí, son 16 bytes"); -} else { - console.log("¡Oh no, es del tamaño incorrecto!"); -} -- -
Antes de que podamos trabajar realmente con este búfer, necesitamos crear una vista. Creemos una vista que trate los datos en el búfer como un arreglo de enteros de 32 bits con signo:
- -let int32View = new Int32Array(buffer); -- -
Ahora podemos acceder a los campos del arreglo como un arreglo normal:
- -for (let i = 0; i < int32View.length; i++) { - int32View[i] = i * 2; -} -- -
Esto completa las 4 entradas en el arreglo (4 entradas de 4 bytes cada una suman 16 bytes en total) con los valores 0
, 2
, 4
y 6
.
Las cosas comienzan a ponerse realmente interesantes cuando consideras que puedes crear múltiples vistas sobre los mismos datos. Por ejemplo, dado el código anterior, podemos continuar así:
- -let int16View = new Int16Array(buffer); - -for (let i = 0; i < int16View.length; i++) { - console.log('Entrada ' + i + ': ' + int16View[i]); -} -- -
Aquí creamos una vista entera de 16 bits que comparte el mismo búfer que la vista existente de 32 bits y sacamos todos los valores en el búfer como enteros de 16 bits. Ahora obtenemos la salida 0
, 0
, 2
, 0
, 4
, 0
, 6
, 0
.
Sin embargo, puedes dar un paso más. Considera esto:
- -int16View[0] = 32; -console.log('La entrada 0 en el arreglo de 32 bits ahora es ' + int32View[0]); -- -
La salida de esto es "La entrada 0 en el arreglo de 32 bits ahora es 32"
.
En otras palabras, los dos arreglos se ven simplemente en el mismo búfer de datos, tratándolo como formatos diferentes. Lo puedes hacer con cualquier {{JSxRef("Global_Objects/TypedArray", "tipo de vista", "#TypedArray_objects")}}.
- -Al combinar un solo búfer con múltiples vistas de diferentes tipos, comenzando con diferentes desplazamientos en el búfer, puedes interactuar con objetos de datos que contienen múltiples tipos de datos. Esto te permite, por ejemplo, interactuar con complejas estructuras de datos WebGL, archivos de datos o estructuras C que necesitas utilizar mientras usas js-ctypes.
- -Considera esta estructura C:
- -struct someStruct { - unsigned long id; - char username[16]; - float amountDue; -};- -
Puedes acceder a un búfer que contiene datos en un formato como este:
- -let buffer = new ArrayBuffer(24); - -// ... lee los datos en el búfer ... - -let idView = new Uint32Array(buffer, 0, 1); -let usernameView = new Uint8Array(buffer, 4, 16); -let amountDueView = new Float32Array(buffer, 20, 1);- -
Luego puedes acceder, por ejemplo, al monto adeudado con amountDueView[0]
.
Después de procesar un arreglo con tipo, a veces es útil volver a convertirla en un arreglo normal para beneficiarse del prototipo {{jsxref("Array")}}. Esto se puede hacer usando {{JSxRef("Array.from()")}}, o usando el siguiente código donde Array.from()
no es compatible.
let typedArray = new Uint8Array([1, 2, 3, 4]), - normalArray = Array.prototype.slice.call(typedArray); -normalArray.length === 4; -normalArray.constructor === Array; -- -
Especificación | -
---|
{{SpecName('ESDraft', '#sec-typedarray-objects', 'TypedArray Objects')}} | -
{{Compat("javascript.builtins.Int8Array")}}
- -