Showdown de código: Ruby vs Javascript

Ruby y JavaScript están a punto de enfrentarse. Ambos lenguajes de secuencias de comandos se escriben dinámicamente y admiten programación orientada a objetos. Examinaremos sus diferencias o similitudes en algunas de sus características más comunes.

Descargo de responsabilidad: aquí solo estamos viendo la sintaxis moderna de JavaScript ES6.

Foto de Pramote Polyamate en 500px

Interpolación de cuerdas

En la programación de computadoras, la interpolación de cadenas es el proceso de inyectar el valor de una variable o una expresión en un literal de cadena.

En Ruby, esto se llama, lo adivinaste, interpolación de cadenas.

Rubí:

first_name = "Martin"
last_name = "Riggs"
pone "Hola, soy # {first_name} # {last_name}".

En Javascript, se puede lograr lo mismo con los literales de plantilla.

JavaScript:

const firstName = 'Martin';
const lastName = 'Riggs';
console.log (`Hola, soy $ {firstName} $ {lastName} .`);

Métodos y funciones.

Wikipedia explica que, en la programación de computadoras, una subrutina es una secuencia de instrucciones del programa que realiza una tarea específica, empaquetada como una unidad. Esta unidad se puede usar en programas donde sea que se realice esa tarea en particular.

En diferentes lenguajes de programación, una subrutina puede llamarse procedimiento, función, rutina, método o subprograma.

Para poder usarse, estas subrutinas deben definirse primero y luego llamarse. En Ruby, se conocen como métodos y en JavaScript, se llaman funciones.

Rubí:

def full_name (nombre, apellido)
  "# {first_name.capitalize} # {last_name.capitalize}"
fin
pone nombre completo ("beatrix", "kiddo")

JavaScript:

función fullName (firstName, lastName) {
  return `$ {firstName.capitalize ()} $ {lastName.capitalize ()}`;
};
console.log (fullName ("beatrix", "kiddo"));

Si está ejecutando los ejemplos anteriores, probablemente haya notado que el ejemplo de JavaScript no funciona, pero arroja un error: Error de tipo no capturado: firstName.capitalize no es una función.

Esto se debe a que JavaScript no define una función de capitalización de forma nativa. Ruby tiene muchos métodos idiomáticos prácticos y ordenados como #capitalize que son realmente convenientes. Para que el ejemplo anterior funcione, necesitaremos usar la cadena prototipo (parche de mono) en el objeto String de JavaScript:

String.prototype.capitalize = function () {
  devuelve this.charAt (0) .toUpperCase () + this.slice (1);
}

Bloques

En Ruby, los bloques son básicamente fragmentos de código sin nombre que se pueden pasar y llamar desde métodos internos. Muchos de los métodos de objetos integrados en Ruby aceptan bloques y estos son una forma conveniente de modificar la forma en que se comportan dichos métodos.

Rubí:

temporizador de def
  start_time = Time.now
  pone "Bloque corriendo ..."
  
  rendimiento
  pone "¡Terminado!"
  end_time = Time.now - start_time
  "Tiempo de ejecución: # {end_time}"
fin
pone el temporizador {(0..10000000) .sort}

¡Hola, JavaScript no tiene bloques, por lo que la implementación anterior no es posible y la comparación es tonta! ¿O es eso? Las funciones de JavaScript pueden aceptar funciones de devolución de llamada como argumentos y si pensamos que los bloques de Ruby se parecen mucho a los métodos anónimos, podemos lograr un resultado similar.

JavaScript:

temporizador de función (devolución de llamada) {
  const startTime = new Date (). getTime ();
  console.log ("Ejecutando devolución de llamada ...");
  
  llamar de vuelta();
  console.log ("¡Terminado!");
  const endTime = new Date (). getTime ();
  return `Tiempo de ejecución: $ {endTime - startTime}`;
};
timer (() => Array.from (Array (10000000) .keys ()). sort ());

Nota: a diferencia de Ruby, JavaScript no tiene un objeto Range integrado. El Array.from (Number) .keys () anterior devuelve un Array de 0 a Number.

Iteraciones idiomáticas

Ruby es conocido por tener iteradores idiomáticos muy agradables para recorrer Arrays (y otros Enumerables o estructuras iterativas).

Rubí:

nombres = ["Tango", "Efectivo", "Dalton", "Riggs"]
nombres.e cada do | nombre |
  pone nombre
fin

Con ES6, iterar a través de una matriz en JavaScript se convierte en una brisa:

JavaScript:

const names = ['Tango', 'Cash', 'Dalton', 'Riggs'];
nombres.porCada (nombre => consola.log (nombre));

Nota: La función Javascript forEach también puede acceder al índice del elemento. En Ruby, usaríamos un iterador diferente para el llamado each_with_index.

Clases y herencia de clases

En la programación orientada a objetos, las clases son plantillas de código para crear objetos, proporcionar valores para el estado (propiedades o atributos del objeto) e implementar comportamientos (como captadores y establecedores para leer y escribir tales propiedades o atributos).

Rubí:

Vehículo de clase
  def initialize (nombre, tipo)
    @name = name
    @type = type
  fin
  nombre def
    @nombre
  fin
  tipo de def
    @tipo
  fin
fin
Clase Car 
diablo = Car.new ("Lamborghini")
pone diablo.name
pone diablo.type

JavaScript:

Vehículo de clase {
 
  constructor (nombre, tipo) {
    this.name = nombre;
    this.type = type;
  }
 
  getName () {
    devuelve this.name;
  }
 
  getType () {
    devuelve this.type;
  }
 
}
El auto de clase extiende el vehículo {
 
  constructor (nombre) {
    super (nombre, 'auto');
  }
}
const diablo = auto nuevo ('Lamborghini');
console.log (diablo.getName ());
console.log (diablo.getType ());

Nota: En el ejemplo anterior, la clase Ruby Vehicle se implementaría típicamente con un lector de atributos para crear los métodos getter para las variables de instancia. Elegí no usar un lector de atributos para tener un aspecto más similar a la implementación de JavaScript.

Desestructuración

El JavaScript moderno introdujo esta cosa realmente genial llamada desestructuración, donde puede asignar elementos dentro de matrices u objetos a variables con una sintaxis concisa.

JavaScript:

firstName, lastName = 'James Bond'.split ();
console.log (`Mi nombre es $ {lastName}, $ {firstName} $ {lastName}`);

¡Seguramente no puedes hacer esto en Ruby!

Rubí:

first_name, last_name = "James Bond" .split
pone "Mi nombre es # {last_name}, # {first_name} # {last_name}"

Nota: Si bien podemos desestructurar matrices en Ruby tanto como lo hacemos en JavaScript, no hay un equivalente de Ruby para desestructurar directamente los hashes.

Operador extendido

JavaScript moderno también ha introducido el operador de propagación que permite expandir expresiones iterables donde se esperan cero o más argumentos o elementos.

JavaScript:

función suma (x, y, z) {
  devuelve x + y + z;
};
números constantes = [1, 2, 3];
console.log (suma (... números);
[a, b, ... rest] = [10, 20, 30, 40, 50];
console.log (a);
console.log (b);
console.log (resto); // el descanso es una matriz!

En Ruby, tenemos el operador splat para esto.

Rubí:

suma de def (x, y, z)
  x + y + z
fin
números = [1, 2, 3]
pone suma (* números)
a, * resto, b = [10, 20, 30, 40, 50]
pone un
pone b
pone descanso # descanso es una matriz!

Nota: Probablemente hayas notado que en Ruby * el descanso está entre las otras variables. Ese es el operador splat se puede colocar en cualquier lugar entre las variables. En JavaScript, el operador de propagación debe ser el último.

Ruby también tiene el operador de doble splat ** para hacer lo mismo en los hashes. La especificación JavaScript ES2018 también introduce el operador de propagación en los objetos.

Palabra final

Como probablemente te hayas dado cuenta, ambos idiomas no son tan diferentes después de todo y, con ES6, JavaScript se ha vuelto cada vez más agradable de escribir. Claro, JavaScript es el idioma del navegador y su bucle de eventos proporciona un comportamiento asincrónico. Por otro lado, Ruby tiene herramientas muy poderosas para hacer metaprogramación y es querido por su sintaxis idiomática. Al final, creo que es beneficioso aprender y conocerlos, ya que a menudo el conocimiento de un lenguaje de programación le dará ideas sobre cómo codificar o abordar un determinado problema en otro.