
La mayoría de los lenguajes de programación surgieron de un antiguo paradigma originado en la época de Fortran. El gurú de JavaScript Douglas Crockford desarraiga estas raíces secas, lo que nos permite pensar en el futuro de la programación y pasar a un nuevo nivel de comprensión de los requisitos para el siguiente lenguaje.
El autor comienza con lo básico: nombres, números, valores lógicos, caracteres y otra información básica. Aprenderá no solo sobre los problemas y dificultades de trabajar con tipos en JavaScript, sino también sobre cómo solucionarlos. Luego comenzará a familiarizarse con las estructuras y funciones de datos para comprender los mecanismos subyacentes, y aprenderá a usar funciones de orden superior y un estilo de programación orientado a objetos sin clases.
Extracto
Cómo funciona el código sin clases
Y crees que eres inteligente fuera de todas las clases y gratis.
John LennonUna de las ideas clave en el desarrollo de la programación orientada a objetos fue un modelo para el intercambio de datos entre las partes del programa. El nombre del método y sus argumentos deben representarse en forma de mensajes. Una llamada al método envía un mensaje al objeto. Cada objeto se caracteriza por su propio comportamiento, que se manifiesta al recibir mensajes específicos. El remitente cree que el destinatario sabe qué hacer con el mensaje.
Un beneficio adicional es el polimorfismo. Cada objeto que reconoce un mensaje en particular tiene derecho a recibirlo. Lo que sucede a continuación depende de la especialización del objeto. Y este es un pensamiento muy productivo.
Desafortunadamente, comenzamos a distraernos con la herencia, un esquema muy efectivo para reutilizar el código. Su importancia está asociada con la capacidad de reducir los costos laborales al desarrollar un programa. La herencia se basa en un plan similar, con la excepción de algunos matices. Podemos decir que algún objeto o clase de objetos es similar a otro objeto o clase de objetos, pero tiene algunas diferencias importantes. En una situación simple, todo funciona muy bien. Cabe recordar que la OOP moderna comenzó con Smalltalk, un lenguaje de programación para niños. A medida que la situación se vuelve más complicada, la herencia se vuelve problemática. Genera una fuerte cohesión de clases. Cambiar una clase puede causar fallas en aquellas clases que dependen de ella. Los módulos de las clases son simplemente inútiles.
Además, observamos una mayor atención a las propiedades, y no a los objetos. Se presta especial atención a los métodos para obtener (obtener métodos) y asignar valores (establecer métodos) a cada propiedad individual, y en proyectos aún menos exitosos, las propiedades están abiertas y pueden cambiarse sin el conocimiento del objeto. Es posible introducir un proyecto más exitoso, donde las propiedades están ocultas y los métodos procesan las transacciones, no solo se ocupan de los cambios de propiedades. Pero este enfoque no se aplica a menudo.
Además, hay demasiada dependencia del tipo. Los tipos se convirtieron en una característica de los idiomas Fortran y posteriores, ya que eran convenientes para los creadores del compilador. Desde entonces, la mitología en torno a los tipos ha crecido, habiendo adquirido afirmaciones extravagantes de que los tipos protegen el programa de errores. A pesar de la devoción por los tipos, los errores no abandonaron la práctica diaria.
Los tipos son respetados y alabados por la detección temprana de errores de cálculo en la etapa de compilación. Cuanto antes se descubra un descuido, menor será el costo requerido para eliminarlo. Pero con una prueba adecuada del programa, todos estos errores de cálculo se detectan muy rápidamente. Por lo tanto, los errores de identificación de tipo se clasifican como de bajo costo.
Los tipos no tienen la culpa de la aparición de errores costosos y difíciles de detectar. Su culpa no está en la aparición de problemas causados por tales errores y que requieren algunos trucos. Los tipos nos pueden empujar a usar métodos de programación oscuros, confusos y dudosos.
Los tipos son como una dieta para bajar de peso. La dieta no está acusada de regresar y aumentar de peso. Tampoco se la considera la causa del sufrimiento o los problemas de salud que causó. Las dietas dan la esperanza de que el peso volverá a una norma saludable y continuaremos comiendo comida chatarra.
La herencia clásica nos permite pensar que creamos programas de alta calidad, mientras cometemos más errores y aplicamos herencias cada vez más ineficientes. Si ignoras las manifestaciones negativas, los tipos parecen ser una gran victoria. Los beneficios son obvios. Pero si observa los tipos más de cerca, notará que los costos exceden los beneficios.
Constructor
En el capítulo 13, trabajamos con fábricas, funciones que devuelven funciones. Ahora podemos hacer algo similar con los constructores: funciones que devuelven objetos que contienen funciones.
Comencemos creando counter_constructor, similar al generador de contadores. Tiene dos métodos, arriba y abajo:
function counter_constructor() { let counter = 0; function up() { counter += 1; return counter; } function down() { counter -= 1; return counter; } return Object.freeze({ up, down }); }
El objeto devuelto está congelado. No puede ser dañado o dañado. El objeto tiene un estado. El contador variable es una propiedad privada del objeto. Puede acceder solo a través de métodos. Y no necesitamos usar esto.
Esta es una circunstancia muy importante. La interfaz del objeto es exclusivamente métodos. Él tiene un caparazón muy fuerte. Obtenemos la mejor encapsulación. No hay acceso directo a los datos. Este es un diseño modular de muy alta calidad.
Un constructor es una función que devuelve un objeto. Los parámetros y las variables del constructor se convierten en propiedades privadas del objeto. No tiene propiedades públicas consistentes en datos. Las funciones internas se convierten en métodos de objeto. Convierten las propiedades en cerradas. Los métodos que caen en un objeto congelado están abiertos.
Los métodos deben implementar transacciones. Supongamos, por ejemplo, que tenemos un objeto persona. Es posible que deba cambiar la dirección de la persona cuyos datos están almacenados en él. Para hacer esto, no necesita un conjunto separado de funciones para cambiar cada elemento de dirección individual. Necesitamos un método que reciba un objeto literal, capaz de describir todas las partes de la dirección que deben cambiarse.
Una de las ideas brillantes en JavaScript es el objeto literal. Esta es una sintaxis agradable y expresiva para agrupar información. Al crear métodos que consuman y creen objetos de datos, puede reducir la cantidad de métodos, aumentando así la integridad del objeto.
Resulta que tenemos dos tipos de objetos.
- Los objetos duros contienen solo métodos. Estos objetos protegen la integridad de los datos contenidos en el cierre. Nos proporcionan polimorfismo y encapsulación.
- Los objetos de datos blandos contienen solo datos. No tienen comportamiento. Esta es solo una colección útil con la que las funciones pueden funcionar.
Se cree que OOP comenzó agregando procedimientos a los registros en el lenguaje Kobol, asegurando así algún tipo de comportamiento. Creo que la combinación de métodos de datos y propiedades fue un importante paso adelante, pero no debería ser el último paso.
Si el objeto duro debe convertirse en una cadena, el método toJSON debe estar habilitado. De lo contrario, JSON.stringify lo verá como un objeto vacío, ignorando los métodos y los datos ocultos (ver capítulo 22).
Opciones de constructor
Una vez que creé un constructor que toma diez argumentos. Era muy difícil de usar, ya que nadie podía recordar el orden de los argumentos. Más tarde se notó que nadie estaba usando el segundo argumento, quería eliminarlo de la lista de parámetros, pero eso rompería todo el código ya desarrollado.
Si fuera prudente, tendría un constructor que toma un objeto como parámetro. Por lo general, se toma de un objeto literal, pero puede provenir de otras fuentes, por ejemplo, del contenido JSON.
Esto proporcionaría muchos beneficios.
- Las líneas clave le dan al código una apariencia documentada. El código es más fácil de leer porque le dice cuál es cada argumento para la persona que llama.
- Los argumentos se pueden organizar en cualquier orden.
- En el futuro, puede agregar nuevos argumentos sin dañar el código existente.
- Los parámetros irrelevantes pueden ser ignorados.
Muy a menudo, un parámetro se usa para inicializar una propiedad privada. Esto se hace de la siguiente manera:
function my_little_constructor(spec) { let { name, mana_cost, colors, type, supertypes, types, subtypes, text, flavor, power, toughness, loyalty, timeshifted, hand, life } = spec;
Este código crea e inicializa 15 variables privadas usando propiedades con los mismos nombres de espec. Si la especificación no tiene una propiedad correspondiente, se inicializa una nueva variable, a la que se le asigna el valor indefinido. Esto le permite completar todos los valores faltantes con valores predeterminados.
Composición
La vívida expresividad y efectividad de JavaScript le permite crear programas en el paradigma clásico, aunque este lenguaje no se aplica a los clásicos. JavaScript también permite mejoras. Podemos trabajar con una composición funcional. Entonces, en lugar de agregar algo como una excepción, puede obtener un poco de esto y aquello. El constructor tiene el siguiente aspecto general:
function my_little_constructor(spec) { let {} = spec; const _ = other_constructor(spec); const = function () {
Su constructor puede llamar a tantos otros constructores como sea necesario para obtener acceso a la administración de estado y al comportamiento que proporcionan. Incluso puede pasarle exactamente el mismo objeto de especificación. Al documentar los parámetros de especificaciones, enumeramos las propiedades que necesita my_little_constructor y las propiedades que necesitan otros constructores.
A veces, simplemente puede agregar los métodos resultantes a un objeto congelado. En otros casos, tenemos nuevos métodos que invocan los métodos recibidos. Esto asegura que el código se reutilice, similar a la herencia, pero sin una fuerte cohesión. Una llamada a función es el esquema de reutilización de código original, y no se ha inventado nada mejor.
Tamaño
Con este enfoque para construir un objeto, se involucra más memoria que cuando se usan prototipos, ya que cada objeto rígido contiene todos los métodos del objeto, y el objeto prototipo contiene un enlace al prototipo que contiene los métodos. ¿Es significativa la diferencia en el consumo de memoria? Comparando la diferencia con los últimos logros en el aumento de la cantidad de memoria, podemos decir: no. Estamos acostumbrados a leer memoria en kilobytes. Y ahora lo consideramos en gigabytes. En este contexto, la diferencia no se siente en absoluto.
La diferencia puede reducirse mejorando la modularidad. El énfasis en las transacciones, no en las propiedades, le permite reducir la cantidad de métodos y, al mismo tiempo, mejorar la conectividad.
El modelo clásico se caracteriza por la uniformidad. Cada objeto debe ser una instancia de una clase. JavaScript elimina estas restricciones. No todos los objetos deben cumplir con reglas tan estrictas.
Por ejemplo, creo que no tiene sentido que los puntos sean necesariamente objetos rígidos con métodos. Un punto puede ser un contenedor simple para dos o tres números. Los puntos se pasan a funciones que son capaces de proyección, interpolación u otra cosa que se puede hacer con puntos. Esto puede ser mucho más productivo que subclasificar puntos para darles un comportamiento especial. Deje que las funciones funcionen.
»Se puede encontrar más información sobre el libro en
el sitio web del editor»
Contenidos»
ExtractoCupón de 25% de descuento para vendedores ambulantes -
JavaScriptTras el pago de la versión en papel del libro, se envía un libro electrónico por correo electrónico.