Movatterモバイル変換


[0]ホーム

URL:


  1. Tecnología web para desarrolladores
  2. JavaScript
  3. Guía de JavaScript
  4. Una reintroducción a JavaScript (Tutorial de JS)

Esta página ha sido traducida del inglés por la comunidad.Aprende más y únete a la comunidad de MDN Web Docs.

View in EnglishAlways switch to English

Una reintroducción a JavaScript (Tutorial de JS)

¿Por qué una reintroducción? PorqueJavaScript es conocido por serel lenguaje de programación más incomprendido. A menudo se le ridiculiza como un juguete, pero debajo de esa capa de engañosa simplicidad, aguardan poderosas características del lenguaje. Ahora un increíble número de aplicaciones de alto perfil utilizan JavaScript, lo cual demuestra que un conocimiento más profundo de esta tecnología es una habilidad importante para cualquier desarrollador web o móvil.

Es útil comenzar con una descripción general de la historia del lenguaje. JavaScript fue creado en 1995 por Brendan Eich mientras era ingeniero en Netscape. JavaScript se lanzó por primera vez con Netscape 2 a principios de 1996. Originalmente se iba a llamar LiveScript, pero se le cambió el nombre en una desafortunada decisión de marketing que intentó capitalizar la popularidad del lenguaje Java de Sun Microsystem, a pesar de que los dos tienen muy poco en común. Esto ha sido una fuente de confusión desde entonces.

Varios meses después, Microsoft lanzó JScript con Internet Explorer 3. Era un JavaScript prácticamente compatible. Varios meses después de eso, Netscape envió JavaScript aEcma International, una organización europea de estándares, que resultó en la primera edición del estándarECMAScript ese año. El estándar recibió una actualización significativa comoECMAScript edición 3 en 1999, y se ha mantenido bastante estable desde entonces. La cuarta edición fue abandonada debido a diferencias políticas sobre la complejidad del lenguaje. Muchas partes de la cuarta edición formaron la base para la edición 5 de ECMAScript, publicada en diciembre de 2009, y para la sexta edición principal del estándar, publicada en junio de 2015.

Nota:Debido a que es más familiar, nos referiremos a ECMAScript como "JavaScript" de ahora en adelante.

A diferencia de la mayoría de los lenguajes de programación, el lenguaje JavaScript no tiene un concepto de entrada o salida. Está diseñado para ejecutarse como un lenguaje descripting en un entorno hospedado, y depende del entorno para proporcionar los mecanismos para comunicarse con el mundo exterior. El entorno de alojamiento más común es el navegador, pero también se pueden encontrar intérpretes de JavaScript en una gran lista de otros lugares, incluidos Adobe Acrobat, Adobe Photoshop, imágenes SVG, el motor de widgets de Yahoo, entornos de lado del servidor comoNode.js, bases de datos NoSQL comoApache CouchDB de código abierto, computadoras integradas, entornos de escritorio completos comoGNOME (una de las IGU —Interfaz Gráfica de Usuario— más populares para sistemas operativos GNU/Linux), y otros.

Información general

JavaScript es un lenguaje dinámico múltiparadigma con tipos y operadores, objetos estándar integrados y métodos. Su sintaxis se basa en los lenguajes Java y C — muchas estructuras de esos lenguajes también se aplican a JavaScript. JavaScript admite la programación orientada a objetos con prototipos de objetos, en lugar de clases (consulta más información sobreherencia prototípica y ES2015clases. JavaScript también admite la programación funcional — debido a que son objetos, las funciones se pueden almacenar en variables y pasarse como cualquier otro objeto.

Comencemos observando los componentes básicos de cualquier lenguaje: los tipos. Los programas JavaScript manipulan valores, y todos esos valores pertenecen a un tipo. Los tipos de JavaScript son:

... oh, yundefined ynull, que son ... ligeramente extraños. YArray, que es un tipo de objeto especial. YFechas (Date) yExpresiones regulares (RegExp), que son objetos que obtienes de forma gratuita. Y para ser técnicamente precisos, las funciones son solo un tipo especial de objeto. Por lo tanto, el diagrama de tipos se parece más a este:

Y también hay algunos tiposError integrados. Sin embargo, las cosas son mucho más fáciles si nos atenemos al primer diagrama, por lo que discutiremos los tipos enumerados allí por ahora.

Números

Los números en JavaScript son "valores IEEE 754 de formato de 64 bits de doble precisión", de acuerdo con las especificaciones.No existen números enteros en JavaScript (exceptoBigInt), por lo que debes tener un poco de cuidado. Ve este ejemplo:

console.log(3 / 2);             // 1.5, not 1console.log(Math.floor(3 / 2)); // 1

Entonces, unentero aparente de hechoimplícitamente es unfloat.

Además, ten cuidado con cosas como:

js
0.1 + 0.2 == 0.30000000000000004;

En la práctica, los valores enteros se tratan como enteros de 32 bits, y algunas implementaciones incluso los almacenan de esa manera hasta que se les pide que realicen una instrucción que sea válida en un Número pero no en un entero de 32 bits. Esto puede ser importante para operaciones bit a bit.

Se admiten losoperadores estándar, incluidas la aritmética de suma, resta, módulo (o resto), etc. También hay un objeto incorporado que no mencionamos anteriormente llamadoMath que proporciona funciones matemáticas avanzadas y constantes:

js
Math.sin(3.5);var circumference = 2 * Math.PI * r;

Puedes convertir una cadena en un número entero usando la funciónparseInt() incorporada. Esta toma la base para la conversión como un segundo argumento opcional, que siempre debes proporcionar:

js
parseInt("123", 10); // 123parseInt("010", 10); // 10

En los navegadores más antiguos, se supone que las cadenas que comienzan con un "0" están en octal (raíz 8), pero este no ha sido el caso desde 2013 más o menos. A menos que estés seguro de tu formato de cadena, puedes obtener resultados sorprendentes en esos navegadores más antiguos:

js
parseInt("010"); //  8parseInt("0x10"); // 16

Aquí, vemos que la funciónparseInt() trata la primera cadena como octal debido al 0 inicial, y la segunda cadena como hexadecimal debido al "0x" inicial. Lanotación hexadecimal todavía está en su lugar; solo se ha eliminado el octal.

Si deseas convertir un número binario en un entero, simplemente cambia la base:

js
parseInt("11", 2); // 3

De manera similar, puedes analizar números de coma flotante utilizando la función incorporadaparseFloat(). A diferencia de su primoparseInt(),parseFloat() siempre usa base 10.

También puedes utilizar el operador+ unario para convertir valores en números:

js
+"42"; // 42+"010"; // 10+"0x10"; // 16

Se devuelve un valor especial llamadoNaN (abreviatura de "Not a Number" o "No es un número") si la cadena no es numérica:

js
parseInt("hello", 10); // NaN

NaN es tóxico: si lo proporcionas como operando para cualquier operación matemática, el resultado también seráNaN:

js
NaN + 5; // NaN

Puedes probar si un valor esNaN utilizando la función incorporadaisNaN():

js
isNaN(NaN); // true

JavaScript también tiene los valores especialesInfinity e-Infinity:

js
1 / 0; //  Infinity-1 / 0; // -Infinity

Puedes probar los valoresInfinity,-Infinity yNaN utilizando la función integradaisFinite():

js
isFinite(1 / 0); // falseisFinite(-Infinity); // falseisFinite(NaN); // false

Nota:Las funcionesparseInt() yparseFloat() analizan una cadena hasta que alcancen un caracter que no es válido para el formato de número especificado, luego devuelve el número analizado hasta ese punto. Sin embargo, el operador "+" simplemente convierte la cadena aNaN si contiene un caracter no válido. Intenta analizar la cadena "10.2abc" con cada método tú mismo en la consola y comprenderás mejor las diferencias.

Strings

Las cadenas en JavaScript son secuencias decaracteres Unicode. Esta debería ser una buena noticia para cualquiera que haya tenido que lidiar con la internacionalización. Exactamente, son secuencias de unidades de código UTF-16; cada unidad de código está representada por un número de 16 bits. Cada caracter Unicode está representado por 1 o 2 unidades de código.

Si deseas representar un solo caracter, simplemente usa una cadena que consta de ese único caracter.

Para encontrar la longitud de una cadena (en unidades de código), accede a su propiedadlenght:

js
"hello".length; // 5

¡Aquí está nuestra primer pincelada con objetos JavaScript! ¿Mencionamos que también puedes usar cadenas comoobjetos? También tienenmétodos que te permiten manipular la cadena y acceder a información sobre la cadena:

js
"hello".charAt(0); // "h""hello, world".replace("world", "mars"); // "hello, mars""hello".toUpperCase(); // "HELLO"

Otros tipos

JavaScript distingue entrenull, que es un valor que indica un no valor deliberado (y solo se puede acceder a él mediante la palabra clavenull), yundefined, que es un valor de tipoundefined que indica una variable no iniciada es decir, que aún no se le ha asignado un valor. Hablaremos de variables más adelante, pero en JavaScript es posible declarar una variable sin asignarle un valor. Si hace esto, el tipo de la variable esundefined.undefined en realidad es una constante.

JavaScript tiene un tipo booleano, con valores posiblestrue yfalse (ambos son palabras clave). Cualquier valor se puede convertir a booleano de acuerdo con las siguientes reglas:

  1. false,0, cadenas vacías (""),NaN,null, yundefined todos se vuelvenfalse.
  2. Todos los demás valores se vuelventrue.

Puedes realizar esta conversión explícitamente utilizando la funciónBoolean():

js
Boolean(""); // falseBoolean(234); // true

Sin embargo, esto rara vez es necesario, ya que JavaScript realizará silenciosamente esta conversión cuando espera un booleano, como en una declaraciónif (ve más adelante). Por esta razón, a veces hablamos simplemente de "valores verdaderos" y "valores falsos", es decir, valores que se convierten entrue yfalse, respectivamente, cuando se convierten en booleanos. Alternativamente, estos valores se pueden llamar "veracidad" y "falsedad", respectivamente.

Operaciones booleanas como&& (and lógico),|| (or lógico) y! (not lógico) son compatibles; ve más adelante.

Variables

Las nuevas variables en JavaScript se declaran utilizando una de tres palabras clave:let,const ovar.

let te permite declarar variables a nivel de bloque. La variable declarada está disponible en elbloque en el que está incluida.

js
let a;let name = "Simon";

El siguiente es un ejemplo de alcance con una variable declarada conlet:

js
// myLetVariable *no* es visible aquífor (let myLetVariable = 0; myLetVariable < 5; myLetVariable++) {  // myLetVariable solo es visible aquí}// myLetVariable *no* es visible aquí

const te permite declarar variables cuyos valores pretendes nunca cambiar. La variable está disponible en elbloque en el que se declara.

js
const Pi = 3.14; // establece la variable PiPi = 1; // arrojará un error porque no puede cambiar una variable constante.

var es la palabra clave declarativa más común. No tiene las restricciones que tienen las otras dos palabras clave. Esto se debe a que tradicionalmente era la única forma de declarar una variable en JavaScript. Una variable declarada con la palabra clavevar está disponible en lafunción en la que se declara.

js
var a;var name = "Simon";

Un ejemplo de ámbito con una variable declarada convar:

js
// myVarVariable *es* visible aquífor (var myVarVariable = 0; myVarVariable < 5; myVarVariable++) {  // myVarVariable es visible para toda la función}// myVarVariable *es* visible aquí

Si declaras una variable sin asignarle ningún valor, su tipo esundefined.

Una diferencia importante entre JavaScript y otros lenguajes como Java es que en JavaScript, los bloques no tienen alcance; solo las funciones tienen alcance. Entonces, si una variable se define usandovar en una declaración compuesta (por ejemplo, dentro de una estructura de controlif), será visible para toda la función. Sin embargo, a partir de ECMAScript 2015, las declaracioneslet yconst te permiten crear variables con alcance de bloque.

Operadores

Los operadores numéricos de JavaScript son+,-,*,/ y% que es el operador de residuo o resto (que es lo mismo que módulo). Los valores se asignan usando=, y también hay declaraciones de asignación compuestas como+= y-=. Estas se extienden hastax = x operador y.

js
x += 5;x = x + 5;

Puedes usar++ y-- para incrementar y disminuir respectivamente. Estos se pueden utilizar como operadores prefijos o sufijos.

Eloperador+ también hace concatenación de cadenas:

js
"hello" + " world"; // "hello world"

Si agregas una cadena a un número (u otro valor), todo se convierte primero en cadena. Esto podría hacerte tropezar:

js
"3" + 4 + 5; // "345"3 + 4 + "5"; // "75"

Agregar una cadena vacía a algo es una forma útil de convertirla en cadena.

Se pueden realizar comparaciones en JavaScript utilizando<,>,<= y>=. Estas funcionan tanto para cadenas como para números. La igualdad es un poco menos sencilla. El operador doble-igual realiza la coerción de tipos si le das diferentes tipos, con resultados a veces interesantes:

js
123 == "123"; // true1 == true; // true

Para evitar la coerción de tipos, usa el operador triple-igual:

js
123 === "123"; // false1 === true; // false

También hay operadores!= y!==.

JavaScript también tieneoperaciones bit a bit. Si quieres usarlas, ahí están.

Estructuras de control

JavaScript tiene un conjunto de estructuras de control similar a otros lenguajes de la familia C. Las declaraciones condicionales son compatibles conif yelse; las puedes encadenarlas si lo deseas:

js
var name = "kittens";if (name == "puppies") {  name += " woof";} else if (name == "kittens") {  name += " meow";} else {  name += "!";}name == "kittens meow";

JavaScript tiene bucleswhile y buclesdo-while. El primero es bueno para bucles básicos; el segundo bucle para donde deseas asegurarte de que el cuerpo del bucle se ejecute por lo menos una vez:

js
while (true) {  // ¡un bucle infinito!}var input;do {  input = get_input();} while (inputIsNotValid(input));

Elbuclefor de JavaScript es igual que el de C y Java: te permite proporcione la información de control para tu bucle en una sola línea.

js
for (var i = 0; i < 5; i++) {  // Se ejecutará 5 veces}

JavaScript también contiene otros dos buclesfor destacados:for...of

js
for (let value of array) {  // haz algo con valor}

yfor...in:

js
for (let property in object) {  // hacer algo con la propiedad del objeto}

Los operadores&& y|| utilizan evaluación de cortocircuito, lo cual significa que la evaluación del segundo operando depende del valor del primero. Esto es útil para verificar objetos nulos antes de acceder a sus atributos:

js
var name = o && o.getName();

O para almacenar en caché los valores (cuando los valores falsos no son válidos):

js
var name = cachedName || (cachedName = getName());

JavaScript tiene un operador ternario para expresiones condicionales:

js
var allowed = age > 18 ? "yes" : "no";

La instrucciónswitch se puede usar para múltiples ramas según un número o cadena:

js
switch (action) {  case "draw":    drawIt();    break;  case "eat":    eatIt();    break;  default:    doNothing();}

Si no agregas una instrucciónbreak, la ejecución "caerá" al siguiente nivel. Esto muy rara vez es lo que deseas; de hecho, vale la pena etiquetar específicamente la caída deliberada con un comentario si realmente lo pretendías para ayudar a la depuración:

js
switch (a) {  case 1: // caída deliberada  case 2:    eatIt();    break;  default:    doNothing();}

La cláusuladefault es opcional. Puedes tener expresiones tanto en la parte del switch como en los casos si lo deseas; las comparaciones tienen lugar entre los dos utilizando el operador===:

js
switch (1 + 3) {  case 2 + 2:    yay();    break;  default:    neverhappens();}

Objetos

Los objetos de JavaScript se pueden considerar como simples colecciones de pares nombre-valor. Como tal, son similares a:

  • Diccionarios en Python.
  • Hashes en Perl y Ruby.
  • Tablas hash en C y C++.
  • HashMaps en Java.
  • Arreglos asociativas en PHP.

El hecho de que esta estructura de datos se utilice tan ampliamente es un testimonio de su versatilidad. Dado que todo (el núcleo, tipos bar) en JavaScript es un objeto, cualquier programa de JavaScript implica naturalmente una gran cantidad de búsquedas en tablas hash. ¡Qué bueno que sean tan rápidas!

La parte "name" es una cadena JavaScript, mientras que el valor puede ser cualquier valor de JavaScript, incluidos más objetos. Esto te permite construir estructuras de datos de complejidad arbitraria.

Hay dos formas básicas de crear un objeto vacío:

js
var obj = new Object();

Y:

js
var obj = {};

Estas son semánticamente equivalentes; la segunda se llama sintaxis literal de objeto y es más conveniente. Esta sintaxis también es el núcleo del formato JSON y se debe preferir en todo momento.

La sintaxis de objeto literal se puede utilizar para iniciar un objeto en su totalidad:

js
var obj = {  name: "Carrot",  for: "Max", // 'for' es una palabra reservada, use '_for' en su lugar.  details: {    color: "orange",    size: 12,  },};

El acceso a los atributos se puede encadenar:

js
obj.details.color; // orangeobj["details"]["size"]; // 12

El siguiente ejemplo crea un prototipo de objeto (Person) y una instancia de ese prototipo (you).

js
function Person(name, age) {  this.name = name;  this.age = age;}// Define un objetovar you = new Person("You", 24);// Estamos creando una nueva persona llamada "You" de 24 años.

Una vez creado, se puede volver a acceder a las propiedades de un objeto de dos formas:

js
// notación de puntosobj.name = "Simon";var name = obj.name;

Y...

js
// notación de corchetesobj["name"] = "Simon";var name = obj["name"];// puedes usar una variable para definir una clavevar user = prompt("¿cuál es su clave?");obj[user] = prompt("¿cuál es su valor?");

Estas también son semánticamente equivalentes. El segundo método tiene la ventaja de que el nombre de la propiedad se proporciona como una cadena, lo cual significa que se puede calcular en tiempo de ejecución. Sin embargo, el uso de este método evita que se apliquen algunas optimizaciones de minificación y del motor de JavaScript. También se puede utilizar para establecer y obtener propiedades con nombrespalabras reservadas:

js
obj.for = "Simon"; // Error de sintaxis, porque 'for' es una palabra reservadaobj["for"] = "Simon"; // trabaja bien

Nota:A partir de ECMAScript 5, las palabras reservadas se pueden utilizar como nombres de propiedad de objeto "en bruto". Esto significa que no necesitan "vestirse" entre comillas al definir objeto literales. Consulta laespecificación de ES5.

Para obtener más información sobre objetos y prototipos, consultaObject.prototype. Para obtener una explicación de los prototipos de objetos y las cadenas de prototipos de objetos, consultaHerencia y la cadena de prototipos.

Nota:A partir de ECMAScript 2015, las claves de objeto se pueden definir mediante la variable en notación de corchetes al crearlas.{[phoneType]: 12345} es posible en lugar de solovar userPhone = {}; userPhone[phoneType] = 12345.

Arreglos

Los arreglos en JavaScript en son realidad un tipo especial de objeto. Funcionan de manera muy parecida a los objetos normales (las propiedades numéricas se pueden acceder naturalmente solo usando la sintaxis[]) pero tienen una propiedad mágica llamada 'length'. Este siempre es uno más que el índice más alto de el arreglo.

Una forma de crear arreglos es la siguiente:

js
var a = new Array();a[0] = "dog";a[1] = "cat";a[2] = "hen";a.length; // 3

Una notación más conveniente es usar un arreglo literal:

js
var a = ["dog", "cat", "hen"];a.length; // 3

Ten en cuenta quearray.length no necesariamente es el número de elementos del arreglo. Considera lo siguiente:

js
var a = ["dog", "cat", "hen"];a[100] = "fox";a.length; // 101

Recuerda — la longitud de el arreglo es uno más que el índice más alto.

Si consultas un índice de arreglo que no existe, obtendrás un valor deundefined:

js
typeof a[90]; // undefined

Si tienes en cuenta lo anterior sobre[] ylength, puedes iterar sobre un arreglo utilizando el siguiente buclefor:

js
for (var i = 0; i < a.length; i++) {  // Haz algo con a[i]}

ES2015 introdujo el bucle más concisofor...of para objetos iterables como arreglos:

js
for (const currentValue of a) {  // Haz algo con currentValue}

También puedes iterar sobre un arreglo utilizando el buclefor...in, sin embargo, este no itera sobre los elementos del arreglo, sino los índices del arreglo. Además, si alguien agrega nuevas propiedades aArray.prototype, también serán iteradas por dicho bucle. Por lo tanto, este tipo de bucle no se recomienda para arreglos.

Otra forma de iterar sobre un arreglo que se agregó con ECMAScript 5 esarr.forEach():

js
["dog", "cat", "hen"].forEach(function (currentValue, index, array) {  // Hacer algo con currentValue o array[index]});

Si deseas agregar un elemento a un arreglo, simplemente hazlo así:

js
a.push(item);

Los arreglos vienen con varios métodos. Consulta también ladocumentación completa para métodos de arreglo.

Nombre del métodoDescripción
a.toString()Devuelve una cadena con eltoString() de cada elemento separado por comas.
a.toLocaleString()Devuelve una cadena con eltoLocaleString() de cada elemento separado por comas.
a.concat(item1[, item2[, ...[, itemN]]])Devuelve un nuevo arreglo con los elementos agregados.
a.join(sep)Convierte el arreglo en una cadena, con valores delimitados por el parámetrosep
a.pop()Elimina y devuelve el último elemento.
a.push(item1, ..., itemN)Agrega elementos al final del arreglo.
a.shift()Elimina y devuelve el primer elemento.
a.unshift(item1[, item2[, ...[, itemN]]])Añade elementos al inicio del arreglo.
a.slice(start[, end])Devuelve un subarreglo.
a.sort([cmpfn])Toma una función de comparación opcional.
a.splice(start, delcount[, item1[, ...[, itemN]]])Te permite modificar un arreglo eliminando una sección y reemplazándola con más elementos.
a.reverse()Invierte el arreglo.

Funciones

Junto con los objetos, las funciones son el componente principal para comprender JavaScript. La función más básica no podría ser mucho más sencilla:

js
function add(x, y) {  var total = x + y;  return total;}

Esto demuestra una función básica. Una función de JavaScript puede tomar 0 o más parámetros con nombre. El cuerpo de la función puede contener tantas declaraciones como desees y puedes declarar tus propias variables que son locales para esa función. La declaraciónreturn se puede usar para devolver un valor en cualquier momento, terminando la función. Si no se utiliza una declaraciónreturn (oreturn vacía sin valor), JavaScript devuelveundefined.

Los parámetros nombrados resultan ser más intuitivos que cualquier otra cosa. Puedes llamar a una función sin pasar los parámetros que espera, en cuyo caso se establecerán enundefined.

js
add(); // NaN// No puedes realizar sumas en undefined

También puedes pasar más argumentos de los que espera la función:

js
add(2, 3, 4); // 5// sumó los dos primeros; el 4 fue ignorado

Eso puede parecer un poco tonto, pero las funciones tienen acceso a una variable adicional dentro de su cuerpo llamadaargumentos, que es un objeto tipo arreglo que contiene todos los valores pasados a la función. Reescribamos la función de suma para tomar tantos valores como queramos:

js
function add() {  var sum = 0;  for (var i = 0, j = arguments.length; i < j; i++) {    sum += arguments[i];  }  return sum;}add(2, 3, 4, 5); // 14

Sin embargo, eso no es más útil que escribir2 + 3 + 4 + 5. Creemos una función de promedio:

js
function avg() {  var sum = 0;  for (var i = 0, j = arguments.length; i < j; i++) {    sum += arguments[i];  }  return sum / arguments.length;}avg(2, 3, 4, 5); // 3.5

Esta es bastante útil, pero parece un poco detallada. Para reducir un poco más este código, podemos considerar la sustitución del uso del arreglo de argumentos a través de lasintaxis del parámetroRest. De esta manera, podemos pasar cualquier número de argumentos a la función manteniendo nuestro código mínimo. Eloperador de parámetrorest se usa en listas de parámetros de función con el formato:...variable e incluirá dentro de esa variable la lista completa de argumentos no capturados a los que se llamó la función.with. También reemplazaremos el buclefor con un buclefor...of para devolver los valores dentro de nuestra variable.

js
function avg(...args) {  var sum = 0;  for (let value of args) {    sum += value;  }  return sum / args.length;}avg(2, 3, 4, 5); // 3.5

Nota:En el código anterior, la variableargs contiene todos los valores que se pasaron a la función.

Es importante tener en cuenta que dondequiera que se coloque el operador de parámetrorest en una declaración de función, almacenará todos los argumentosdespués de su declaración, pero no antes.es decir, functionavg(firstValue,...args) almacenará el primer valor pasado a la función en la variablefirstValue y los argumentos restantes enargs. Esa es otra característica útil del lenguaje, pero nos lleva a un nuevo problema. La funciónavg() toma una lista de argumentos separados por comas, pero ¿qué sucede si deseas encontrar el promedio de un arreglo? Simplemente, podrías reescribir la función de la siguiente manera:

js
function avgArray(arr) {  var sum = 0;  for (var i = 0, j = arr.length; i < j; i++) {    sum += arr[i];  }  return sum / arr.length;}avgArray([2, 3, 4, 5]); // 3.5

Pero sería bueno poder reutilizar la función que ya hemos creado. Afortunadamente, JavaScript te permite llamar a una función con un arreglo arbitrario de argumentos, usando el métodoapply() de cualquier objeto función.

js
avg.apply(null, [2, 3, 4, 5]); // 3.5

El segundo argumento deapply() es el arreglo que se utilizará comoarguments; el primero se explicará más adelante. Esto enfatiza el hecho de que las funciones también son objetos.

Nota:Puedes lograr el mismo resultado utilizando eloperador de propagación en la llamada de función.

Por ejemplo:avg(...numbers)

JavaScript te permite crear funciones anónimas.

js
var avg = function () {  var sum = 0;  for (var i = 0, j = arguments.length; i < j; i++) {    sum += arguments[i];  }  return sum / arguments.length;};

Esto semánticamente es equivalente a la formafunction avg(). Es extremadamente poderosa, ya que te permite colocar una definición de función completa en cualquier lugar donde normalmente colocarías una expresión. Esto permite todo tipo de ingeniosos trucos. Aquí hay una forma de "ocultar" algunas variables locales — como alcance de bloque en C:

js
var a = 1;var b = 2;(function () {  var b = 3;  a += b;})();a; // 4b; // 2

JavaScript te permite llamar a funciones de forma recursiva. Esto es particularmente útil para tratar con estructuras de árbol, como las que se encuentran en el DOM del navegador.

js
function countChars(elm) {  if (elm.nodeType == 3) {    // TEXT_NODE    return elm.nodeValue.length;  }  var count = 0;  for (var i = 0, child; (child = elm.childNodes[i]); i++) {    count += countChars(child);  }  return count;}

Esto resalta un problema potencial con las funciones anónimas: ¿cómo las llama de forma recursiva si no tienen un nombre? JavaScript te permite nombrar expresiones de función para esto. Puedes utilizarIIFE (expresiones de función invocadas inmediatamente) con nombre como se muestra a continuación:

js
var charsInBody = (function counter(elm) {  if (elm.nodeType == 3) {    // TEXT_NODE    return elm.nodeValue.length;  }  var count = 0;  for (var i = 0, child; (child = elm.childNodes[i]); i++) {    count += counter(child);  }  return count;})(document.body);

El nombre proporcionado a una expresión de función como arriba solo está disponible para el alcance de la función. Esto permite que el motor realice más optimizaciones y da como resultado un código más legible. El nombre también aparece en el depurador y en algunos seguimientos de la pila, lo cual puede ahorrarte tiempo al depurar.

Ten en cuenta que las funciones de JavaScript en sí mismas son objetos, como todo lo demás en JavaScript, y puedes agregar o cambiar propiedades en ellas tal como hemos visto anteriormente en la sección Objetos.

Objetos personalizados

Nota:Para obtener una descripción más detallada de la programación orientada a objetos en JavaScript, consultaIntroducción a JavaScript orientado a objetos.

En la programación clásica orientada a objetos, los objetos son colecciones de datos y métodos que operan sobre esos datos. JavaScript es un lenguaje basado en prototipos que no contiene una declaración de clase, como la encontrarías en C++ o Java (esto, a veces es confuso para los programadores acostumbrados a lenguajes con una declaración de clase). En cambio, JavaScript usa funciones como clases. Consideremos un objetoperson con camposfirst ylast name. Hay dos formas de mostrar el nombre: como "primero último" o como "último, primero". Usando las funciones y objetos que hemos explicado anteriormente, podríamos mostrar los datos de esta manera:

js
function makePerson(first, last) {  return {    first: first,    last: last,  };}function personFullName(person) {  return person.first + " " + person.last;}function personFullNameReversed(person) {  return person.last + ", " + person.first;}var s = makePerson("Simon", "Willison");personFullName(s); // "Simon Willison"personFullNameReversed(s); // "Willison, Simon"

Esto funciona, pero es bastante feo. Terminas con docenas de funciones en tu espacio de nombres global. Lo que realmente necesitamos es una forma de enlazar una función a un objeto. Dado que las funciones son objetos, esto es fácil:

js
function makePerson(first, last) {  return {    first: first,    last: last,    fullName: function () {      return this.first + " " + this.last;    },    fullNameReversed: function () {      return this.last + ", " + this.first;    },  };}var s = makePerson("Simon", "Willison");s.fullName(); // "Simon Willison"s.fullNameReversed(); // "Willison, Simon"

Nota sobre la palabra clavethis. Usada dentro de una función,this se refiere al objeto actual. Lo que realmente significa está especificado por la forma en que llamaste a esa función. Si lo llamaste usandonotación de puntos o notación de corchetes en un objeto, ese objeto se convierte enthis. Si la notación de puntos no se usó para la llamada,this se refiere al objeto global.

Ten en cuenta quethis es una frecuente causa de errores. Por ejemplo:

js
var s = makePerson("Simon", "Willison");var fullName = s.fullName;fullName(); // undefined undefined

Cuando llamamos afullName() solo, sin usars.fullName(),this está vinculado al objeto global. Debido a que no hay variables globales llamadasfirst olast obtenemosundefined para cada una.

Podemos aprovechar la palabra clavethis para mejorar nuestra funciónmakePerson:

js
function Person(first, last) {  this.first = first;  this.last = last;  this.fullName = function () {    return this.first + " " + this.last;  };  this.fullNameReversed = function () {    return this.last + ", " + this.first;  };}var s = new Person("Simon", "Willison");

Hemos introducido otra palabra clave:new.new está fuertemente relacionado conthis. Crea un nuevo objeto vacío y luego llama a la función especificada, conthis configurado para ese nuevo objeto. Sin embargo, ten en cuenta que la función especificada conthis no devuelve un valor, sino que simplemente modifica el objetothis. Esnew que devuelve el objetothis al sitio que realiza la llamada. Las funciones que están diseñadas para ser llamadas pornew se denominan funciones constructoras. La práctica común es poner en mayúscula estas funciones como recordatorio para llamarlas connew.

La función mejorada todavía tiene el mismo error al llamar afullName() sola.

Nuestros objetosperson están mejorando, pero todavía tienen algunos bordes desagradables. Cada vez que creamos un objetoperson, estamos creando dos nuevos objetos de función dentro de él, ¿no sería mejor si este código fuera compartido?

js
function personFullName() {  return this.first + " " + this.last;}function personFullNameReversed() {  return this.last + ", " + this.first;}function Person(first, last) {  this.first = first;  this.last = last;  this.fullName = personFullName;  this.fullNameReversed = personFullNameReversed;}

Eso es mejor: estamos creando las funciones como métodos solo una vez y asignándoles referencias dentro del constructor. ¿Podemos hacer algo mejor que eso? La respuesta es sí:

js
function Person(first, last) {  this.first = first;  this.last = last;}Person.prototype.fullName = function () {  return this.first + " " + this.last;};Person.prototype.fullNameReversed = function () {  return this.last + ", " + this.first;};

Person.prototype es un objeto compartido por todas las instancias dePerson. Forma parte de una cadena de búsqueda (que tiene un nombre especial, "cadena de prototipos"): cada vez que intentes acceder a una propiedad dePerson que no esté configurada, JavaScript revisaráPerson.prototype para ver si esa propiedad existe allí. Como resultado, todo lo asignado aPerson.prototype pasa a estar disponible para todas las instancias de ese constructor a través del objetothis.

Esta es una herramienta increíblemente poderosa. JavaScript te permite modificar el prototipo de algo en cualquier momento en tu programa, lo cual significa que —en tiempo de ejecución— puedes agregar métodos adicionales a los objetos existentes:

js
var s = new Person("Simon", "Willison");s.firstNameCaps(); // TypeError en la línea 1: s.firstNameCaps no es una funciónPerson.prototype.firstNameCaps = function () {  return this.first.toUpperCase();};s.firstNameCaps(); // "SIMON"

Curiosamente, también puedes agregar cosas al prototipo de objetos JavaScript integrados. Agreguemos un método aString que devuelva esa cadena a la inversa:

js
var s = "Simon";s.reversed(); // TypeError en la línea 1: s.reversed no es una funciónString.prototype.reversed = function () {  var r = "";  for (var i = this.length - 1; i >= 0; i--) {    r += this[i];  }  return r;};s.reversed(); // nomiS

¡Nuestro métodonew funciona incluso con cadenas literales!

js
"Esto ahora se puede revertir".reversed(); // ritrever edeup es aroha otsE

Como se mencionó anteriormente, el prototipo forma parte de una cadena. La raíz de esa cadena esObject.prototype, cuyos métodos incluyentoString(); es este método el que se llama cuando intentas representar un objeto como una cadena. Esto es útil para depurar nuestros objetosPerson:

js
var s = new Person("Simon", "Willison");s.toString(); // [object Object]Person.prototype.toString = function () {  return "<Person: " + this.fullName() + ">";};s.toString(); // "<Person: Simon Willison>"

¿Recuerda cómoavg.apply() tenía un primer argumentonull? Ahora lo podemos revisar. El primer argumento deapply() es el objeto que se debe tratar como 'this'. Por ejemplo, aquí hay una implementación trivial denew:

js
function trivialNew(constructor, ...args) {  var o = {}; // Crea un objeto  constructor.apply(o, args);  return o;}

Esta no es una réplica exacta denew ya que no configura la cadena de prototipos (sería difícil de ilustrar). Esto no es algo que use con mucha frecuencia, pero es útil conocerlo. En este fragmento,...args (incluidos los puntos suspensivos) se denomina "argumentos rest" — como su nombre indica, contiene el resto de los argumentos.

Llamar a...

js
var bill = trivialNew(Person, "William", "Orange");

...por tanto, casi es equivalente a

js
var bill = new Person("William", "Orange");

apply() tiene una función hermana llamadacall(), que nuevamente te permite establecerthis pero toma una lista de argumentos expandida en lugar de un arreglo.

js
function lastNameCaps() {  return this.last.toUpperCase();}var s = new Person("Simon", "Willison");lastNameCaps.call(s);// Es lo mismo que:s.lastNameCaps = lastNameCaps;s.lastNameCaps(); // WILLISON

Funciones internas

Las declaraciones de función de JavaScript están permitidas dentro de otras funciones. Hemos visto esto una vez antes, con la funciónmakePerson() anterior. Un detalle importante de las funciones anidadas en JavaScript es que pueden acceder a las variables en el alcance de su función padre:

js
function parentFunc() {  var a = 1;  function nestedFunc() {    var b = 4; // parentFunc no puede usar esto    return a + b;  }  return nestedFunc(); // 5}

Esto proporciona una gran utilidad para escribir un código más fácil de mantener. Si una función llamada se basa en una o dos funciones que no son útiles para ninguna otra parte de tu código, puedes anidar esas funciones de utilidad dentro de ella. Esto mantiene baja la cantidad de funciones que están en el alcance global, lo cual siempre es bueno.

Esto también contrarresta el atractivo de las variables globales. Al escribir código complejo, a menudo es tentador utilizar variables globales para compartir valores entre múltiples funciones, lo que conduce a un código difícil de mantener. Las funciones anidadas pueden compartir variables en su padre, por lo que puedes usar ese mecanismo para unir funciones cuando tenga sentido sin contaminar tu espacio de nombres global — "globales locales" si lo deseas. Esta técnica se debe usar con precaución, pero es una útil habilidad.

Cierres

Esto nos lleva a una de las abstracciones más poderosas que JavaScript tiene para ofrecer — pero potencialmente, también la más confusa. ¿Qué hace esta?

js
function makeAdder(a) {  return function (b) {    return a + b;  };}var add5 = makeAdder(5);var add20 = makeAdder(20);add5(6); // ?add20(7); // ?

El nombre de la funciónmakeAdder() lo debería revelar: crea nuevas funciones 'adder', cada una de las cuales, cuando se llama con un argumento, lo suma al argumento con el que fue creada.

Lo que está sucediendo aquí es más o menos lo mismo que sucedía anteriormente con las funciones internas: una función definida dentro de otra función tiene acceso a las variables de la función externa. La única diferencia aquí es que la función externa ha regresado y, por lo tanto, el sentido común parece dictar que sus variables locales ya no existen. Pero existen todavía — de lo contrario, las funciones de suma no podrían funcionar. Además, hay dos diferentes "copias" de las variables locales demakeAdder(): una en la quea es 5 y la otra en la quea es 20. Entonces, el resultado de las llamadas a esa función es el siguiente:

js
add5(6); // returns 11add20(7); // devuelve 27

Esto es lo que está sucediendo realmente. Siempre que JavaScript ejecuta una función, se crea un objeto 'scope' para contener las variables locales creadas dentro de esa función. Se inicia con cualquier variable pasada como parámetros de función. Esto es similar al objeto global en el que viven todas las variables y funciones globales, pero con un par de importantes diferencias: en primer lugar, se crea un objeto de alcance completamente nuevo cada vez que una función se comienza a ejecutar y, en segundo lugar, a diferencia del objeto global (que es accesible comothis y en los navegadores comowindow) no se puede acceder directamente a estos objetosscope desde tu código JavaScript. No hay ningún mecanismo para iterar sobre las propiedades del objetoscope actual, por ejemplo.

Entonces, cuando se llama amakeAdder(), se crea un objetoscope con una propiedad:a, que es el argumento que se pasa a la funciónmakeAdder().makeAdder() luego devuelve una función recién creada. Normalmente, el recolector de basura de JavaScript limpiaría el objetoscope creado paramakeAdder() en este punto, pero la función devuelta mantiene una referencia a ese objeto de ámbito. Como resultado, el objetoscope no será recolectado como basura hasta que no haya más referencias al objeto función quemakeAdder() devolvió.

Los objetosscope forman una cadena llamada cadena de ámbito, similar a la cadena de prototipos utilizada por el sistema de objetos de JavaScript.

Uncierre es la combinación de una función y el objetoscope en el que se creó. Los cierres te permiten guardar el estado — como tal, a menudo se pueden usar en lugar de objetos. Puedes encontrarvarias presentaciones excelentes de los cierres.

Help improve MDN

Learn how to contribute

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp