JavaScript - Características

-

Características principales

JavaScript tiene varias características principales que lo convierten en un lenguaje de programación poderoso y flexible para el desarrollo web. Estas características incluyen variables y tipos de datos, operadores, control de flujo y funciones.

Variables y tipos de datos

En JavaScript, puedes declarar variables usando las palabras clave var, let o const. var es la forma tradicional de declarar variables, mientras que let y const se introdujeron en ES6 (ECMAScript 2015) para proporcionar alcance de bloque e inmutabilidad.

JavaScript tiene varios tipos de datos primitivos:

Tipo de dato Descripción
number Representa valores numéricos, tanto enteros como números de punto flotante
string Representa datos textuales, encerrados en comillas simples o dobles
boolean Representa un valor lógico, ya sea true o false
null Representa un valor nulo deliberado
undefined Representa una variable que ha sido declarada pero no se le ha asignado un valor

JavaScript también tiene un tipo de dato object, que puede contener colecciones de pares clave-valor o estructuras más complejas.

JavaScript es un lenguaje de tipado dinámico, lo que significa que las variables pueden contener valores de cualquier tipo de dato, y el tipo de una variable puede cambiar durante la ejecución. Esta flexibilidad se logra mediante la coerción y conversión de tipos, donde JavaScript convierte automáticamente valores de un tipo a otro cuando es necesario.

Operadores

JavaScript proporciona una variedad de operadores para realizar operaciones con valores:

  • Operadores aritméticos: +, -, *, /, %, ++, --
  • Operadores de asignación: =, +=, -=, *=, /=, %=
  • Operadores de comparación: ==, ===, !=, !==, >, <, >=, <=
  • Operadores lógicos: &&, ||, !
  • Operador ternario: condición ? valor1 : valor2

Control de flujo

JavaScript ofrece varias declaraciones de control de flujo que permiten controlar la ejecución del código basado en ciertas condiciones o repetir bloques de código múltiples veces.

  • Declaraciones if...else: Ejecutan un bloque de código si una condición especificada es verdadera, o otro bloque de código si la condición es falsa
  • Declaración switch: Evalúa una expresión y ejecuta el bloque de código correspondiente según el caso que coincida
  • Bucle for: Repite un bloque de código un número específico de veces
  • Bucles while y do...while: Repiten un bloque de código mientras una condición especificada sea verdadera
  • Declaraciones break y continue: Alteran el flujo de los bucles terminando el bucle o saltando a la siguiente iteración

Funciones

Las funciones son bloques de código reutilizables que realizan tareas específicas. En JavaScript, puedes definir funciones usando la palabra clave function seguida del nombre de la función y un conjunto de paréntesis que contienen parámetros opcionales.

Consejo: Declaración de función

function saludar(nombre) {
  console.log("¡Hola, " + nombre + "!");
}

Las funciones pueden aceptar parámetros como entrada y devolver valores usando la palabra clave return. Se pueden llamar por su nombre seguido de paréntesis que contienen los argumentos requeridos.

JavaScript también admite expresiones de función, donde las funciones pueden asignarse a variables o pasarse como argumentos a otras funciones.

Consejo: Expresión de función

const cuadrado = function(x) {
  return x * x;
};

Las funciones flecha, introducidas en ES6, proporcionan una sintaxis concisa para definir funciones, particularmente cuando se usan como callbacks o en patrones de programación funcional.

Consejo: Función flecha

const multiplicar = (a, b) => a * b;

Estas características principales forman la base de JavaScript y son esenciales para escribir programas desde básicos hasta complejos en el desarrollo web. Comprender y dominar estas características te permitirá crear aplicaciones web dinámicas e interactivas.

Funciones avanzadas

JavaScript tiene muchas funciones avanzadas que te permiten escribir código más complejo y eficiente. Estas funciones incluyen objetos y arrays, clases y herencia, programación asíncrona y manejo de errores.

Objetos y Arrays

Los objetos y arrays son estructuras de datos importantes en JavaScript. Los objetos almacenan colecciones de pares clave-valor, mientras que los arrays almacenan listas ordenadas de valores.

Para crear un objeto, puedes usar la notación literal de objeto o el constructor Object. Puedes acceder y modificar las propiedades del objeto usando la notación de punto o la notación de corchetes.

Consejo: Creación y acceso a propiedades de objetos

const person = {
  name: "John",
  age: 30,
  city: "New York"
};

console.log(person.name); // Resultado: "John"
person.age = 31;
console.log(person["city"]); // Resultado: "New York"

Los arrays se crean usando la notación literal de array o el constructor Array. Puedes acceder y modificar los elementos del array usando su índice.

Consejo: Creación y acceso a elementos de arrays

const fruits = ["apple", "banana", "orange"];

console.log(fruits[0]); // Resultado: "apple"
fruits[1] = "grape";
console.log(fruits); // Resultado: ["apple", "grape", "orange"]

Los objetos y arrays tienen métodos integrados que te permiten realizar operaciones comunes, como agregar o eliminar elementos, buscar valores y modificar datos.

JavaScript también admite la desestructuración, que te permite extraer valores de objetos y arrays y asignarlos a variables de forma concisa.

Consejo: Desestructuración de objetos y arrays

const { name, age } = person;
console.log(name); // Resultado: "John"

const [first, second] = fruits;
console.log(second); // Resultado: "grape"

Clases y Herencia

JavaScript admite la programación orientada a objetos a través de clases y herencia. Las clases son plantillas para crear objetos con propiedades y métodos específicos.

Para definir una clase, se usa la palabra clave class seguida del nombre de la clase. Dentro de la clase, puedes definir un método constructor para inicializar las propiedades del objeto y otros métodos para definir el comportamiento del objeto.

Consejo: Definición de una clase

class Rectangle {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }

  getArea() {
    return this.width * this.height;
  }
}

Puedes crear instancias de una clase usando la palabra clave new seguida del nombre de la clase y cualquier argumento requerido.

Consejo: Creación de una instancia de clase

const rect = new Rectangle(5, 3);
console.log(rect.getArea()); // Resultado: 15

JavaScript también admite herencia, lo que te permite crear nuevas clases basadas en clases existentes. Puedes usar la palabra clave extends para crear una subclase que herede propiedades y métodos de una superclase.

Consejo: Herencia en JavaScript

class Square extends Rectangle {
  constructor(side) {
    super(side, side);
  }
}

const square = new Square(4);
console.log(square.getArea()); // Resultado: 16

Las subclases pueden sobrescribir métodos de la superclase usando el mismo nombre de método. También pueden llamar al método de la superclase usando la palabra clave super.

Programación Asíncrona

JavaScript es un lenguaje de un solo hilo, lo que significa que el código se ejecuta secuencialmente. Sin embargo, JavaScript proporciona formas de manejar operaciones asíncronas, como realizar solicitudes HTTP o leer archivos, sin bloquear la ejecución de otro código.

En el pasado, la programación asíncrona en JavaScript se realizaba mediante callbacks. Un callback es una función que se pasa como argumento a otra función y se ejecuta cuando se completa la operación asíncrona.

Consejo: Programación asíncrona con callbacks

function fetchData(callback) {
  // Simulando una operación asíncrona
  setTimeout(() => {
    const data = "Hello, world!";
    callback(data);
  }, 1000);
}

fetchData((data) => {
  console.log(data); // Resultado: "Hello, world!"
});

Sin embargo, los callbacks pueden llevar a código anidado y complejo, conocido como "callback hell". Para solucionar este problema, JavaScript introdujo las Promesas, que proporcionan una mejor manera de manejar operaciones asíncronas.

Las Promesas representan la eventual finalización o fallo de una operación asíncrona y te permiten encadenar múltiples operaciones asíncronas usando los métodos .then() y .catch().

Consejo: Programación asíncrona con Promesas

function fetchData() {
  return new Promise((resolve, reject) => {
    // Simulando una operación asíncrona
    setTimeout(() => {
      const data = "Hello, world!";
      resolve(data);
    }, 1000);
  });
}

fetchData()
  .then((data) => {
    console.log(data); // Resultado: "Hello, world!"
  })
  .catch((error) => {
    console.error(error);
  });

ES2017 introdujo las palabras clave async y await, que proporcionan una sintaxis que se parece más a código síncrono para trabajar con Promesas. Dentro de una función async, puedes usar la palabra clave await para pausar la ejecución hasta que se resuelva una Promesa.

Consejo: Programación asíncrona con async/await

async function fetchData() {
  // Simulando una operación asíncrona
  const data = await new Promise((resolve) => {
    setTimeout(() => {
      resolve("Hello, world!");
    }, 1000);
  });
  return data;
}

fetchData().then((data) => {
  console.log(data); // Resultado: "Hello, world!"
});

El bucle de eventos y la pila de llamadas de JavaScript trabajan juntos para gestionar la ejecución de código síncrono y asíncrono. El bucle de eventos comprueba continuamente la pila de llamadas y la cola de tareas, ejecutando tareas de la cola de tareas cuando la pila de llamadas está vacía.

Manejo de Errores

El manejo de errores es una parte importante de la escritura de código JavaScript robusto. JavaScript proporciona la declaración try...catch para manejar excepciones que puedan ocurrir durante la ejecución del código.

Puedes envolver el código que puede lanzar un error dentro de un bloque try, y especificar el código para manejar el error en el bloque catch.

Consejo: Manejo de errores con try...catch

try {
  // Código que puede lanzar un error
  throw new Error("¡Algo salió mal!");
} catch (error) {
  console.error(error.message); // Resultado: "¡Algo salió mal!"
}

Puedes usar la palabra clave throw para lanzar tus propios errores u objetos de error personalizados. Esto te permite manejar diferentes tipos de errores de manera específica.

Consejo: Lanzamiento de errores personalizados

function divide(a, b) {
  if (b === 0) {
    throw new Error("¡División por cero!");
  }
  return a / b;
}

try {
  console.log(divide(10, 0));
} catch (error) {
  console.error(error.message); // Resultado: "¡División por cero!"
}

Características de ES6+

JavaScript ha evolucionado a lo largo de los años, y ECMAScript 2015 (ES6) introdujo nuevas características que se han adoptado ampliamente en el desarrollo moderno de JavaScript. Estas características buscan hacer el lenguaje más expresivo, conciso y fácil de usar. Aquí están algunas de las características notables de ES6+.

Literales de plantilla

Los literales de plantilla, también conocidos como cadenas de plantilla, proporcionan una forma de crear y manipular cadenas en JavaScript. Ofrecen dos ventajas principales sobre la concatenación tradicional de cadenas:

  1. Cadenas multilínea: Los literales de plantilla permiten crear cadenas multilínea sin necesidad de caracteres de escape o concatenación. Puedes envolver el contenido de tu cadena en comillas invertidas ( ) e incluir saltos de línea directamente dentro de la cadena.

Consejo: Cadena multilínea

const cadenaMulitlinea = `
  Esto es una
  cadena multilínea
  usando literales de plantilla.
`;
  1. Interpolación de cadenas: Los literales de plantilla admiten la interpolación de cadenas, lo que permite incrustar expresiones o variables directamente dentro de la cadena. Al envolver la expresión o variable en ${}, puedes incorporar valores dinámicos en tus cadenas.

Consejo: Interpolación de cadenas

const nombre = "Juan";
const edad = 30;
const mensaje = `Mi nombre es ${nombre} y tengo ${edad} años.`;
console.log(mensaje); // Salida: "Mi nombre es Juan y tengo 30 años."

Asignación por desestructuración

La asignación por desestructuración es una forma de extraer valores de objetos o arreglos y asignarlos a variables. Proporciona una sintaxis concisa para desempaquetar valores de estructuras de datos.

  1. Desestructuración de objetos: La desestructuración de objetos permite extraer propiedades específicas de un objeto y asignarlas a variables con un nombre correspondiente.

Consejo: Desestructuración de objetos

const persona = {
  nombre: "Juan",
  edad: 30,
  ciudad: "Madrid"
};

const { nombre, edad } = persona;
console.log(nombre); // Salida: "Juan"
console.log(edad); // Salida: 30
  1. Desestructuración de arreglos: La desestructuración de arreglos permite extraer valores de un arreglo basándose en su posición y asignarlos a variables.

Consejo: Desestructuración de arreglos

const numeros = [1, 2, 3, 4, 5];
const [a, b, ...resto] = numeros;
console.log(a); // Salida: 1
console.log(b); // Salida: 2
console.log(resto); // Salida: [3, 4, 5]

La asignación por desestructuración también admite valores predeterminados, que se utilizan cuando el valor extraído es indefinido, y permite renombrar variables durante el proceso de asignación.

Funciones flecha

Las funciones flecha proporcionan una sintaxis concisa para definir funciones en JavaScript. Ofrecen una alternativa compacta a las expresiones de función tradicionales.

  1. Sintaxis concisa: Las funciones flecha eliminan la necesidad de la palabra clave function y utilizan la sintaxis => para definir la función.

Consejo: Función flecha - Sintaxis concisa

const saludar = (nombre) => {
  return `¡Hola, ${nombre}!`;
};
console.log(saludar("Juan")); // Salida: "¡Hola, Juan!"

Si el cuerpo de la función consiste en una sola expresión, puedes omitir las llaves y la palabra clave return, haciendo la sintaxis aún más concisa.

Consejo: Función flecha - Expresión única

const cuadrado = (x) => x * x;
console.log(cuadrado(5)); // Salida: 25
  1. Vinculación léxica de this: Las funciones flecha tienen una vinculación léxica de this, lo que significa que heredan el valor de this del ámbito circundante. Este comportamiento es útil cuando se trabaja con métodos de objetos o funciones de devolución de llamada.

Consejo: Función flecha - Vinculación léxica de 'this'

const persona = {
  nombre: "Juan",
  saludar: function() {
    setTimeout(() => {
      console.log(`¡Hola, ${this.nombre}!`);
    }, 1000);
  }
};
persona.saludar(); // Salida: "¡Hola, Juan!" (después de 1 segundo)

Módulos

ES6 introdujo un sistema de módulos estandarizado para JavaScript, permitiéndote organizar tu código en módulos reutilizables y encapsulados. Los módulos proporcionan una forma de definir y compartir código entre diferentes archivos o proyectos.

  1. Exportación de módulos: Para hacer que un valor, función o clase esté disponible para su uso en otros módulos, necesitas exportarlo usando la palabra clave export.

Consejo: Exportación de módulos

// matematicas.js
export function sumar(a, b) {
  return a + b;
}

export const PI = 3.14159;
  1. Importación de módulos: Para usar valores, funciones o clases de otro módulo, necesitas importarlos usando la palabra clave import.

Consejo: Importación de módulos

// principal.js
import { sumar, PI } from './matematicas.js';

console.log(sumar(2, 3)); // Salida: 5
console.log(PI); // Salida: 3.14159

Los módulos también admiten exportaciones predeterminadas, que permiten exportar un solo valor como la exportación predeterminada de un módulo, y exportaciones con nombre, que permiten exportar múltiples valores con nombre desde un módulo.

Operadores de reposo y propagación

Los operadores de reposo y propagación (...) proporcionan una forma de trabajar con múltiples elementos de manera concisa.

  1. Parámetros de reposo: El operador de reposo permite capturar múltiples argumentos pasados a una función como un arreglo.

Consejo: Parámetros de reposo

function suma(...numeros) {
  return numeros.reduce((acc, curr) => acc + curr, 0);
}
console.log(suma(1, 2, 3, 4, 5)); // Salida: 15
  1. Operador de propagación: El operador de propagación permite propagar los elementos de un arreglo u objeto en otro arreglo u objeto.

Consejo: Operador de propagación

const numeros = [1, 2, 3];
const nuevosNumeros = [...numeros, 4, 5];
console.log(nuevosNumeros); // Salida: [1, 2, 3, 4, 5]

const persona = { nombre: "Juan", edad: 30 };
const nuevaPersona = { ...persona, ciudad: "Madrid" };
console.log(nuevaPersona); // Salida: { nombre: "Juan", edad: 30, ciudad: "Madrid" }

Estas son algunas de las características notables de ES6+ que se han introducido en JavaScript. Otras características incluyen parámetros de función predeterminados, literales de objeto mejorados, clases, promesas y más. Estas características han mejorado en gran medida la expresividad, legibilidad y funcionalidad del lenguaje, haciendo que el desarrollo en JavaScript sea más agradable y eficiente.