Saltar al contenido

oop – ¿Tiene JavaScript el tipo de interfaz (como la ‘interfaz’ de Java)?

octubre 20, 2021
apple touch icon@2

No existe la noción de «esta clase debe tener estas funciones» (es decir, sin interfaces per se), porque:

  1. La herencia de JavaScript se basa en objetos, no en clases. Eso no es gran cosa hasta que te das cuenta:
  2. JavaScript es un extremadamente lenguaje escrito dinámicamente: puede crear un objeto con los métodos adecuados, lo que lo haría conforme a la interfaz, y luego indefinir todas las cosas que lo hicieron conformarse. Sería muy fácil subvertir el sistema de tipos, ¡incluso accidentalmente! – que no valdría la pena intentar crear un sistema de tipos en primer lugar.

En cambio, JavaScript usa lo que se llama escribiendo pato. (Si camina como un pato y grazna como un pato, por lo que a JS le importa, es un pato). Si su objeto tiene métodos quack (), walk () y fly (), el código puede usarlo donde lo espere. un objeto que puede caminar, graznar y volar, sin requerir la implementación de alguna interfaz «Duckable». La interfaz es exactamente el conjunto de funciones que usa el código (y los valores de retorno de esas funciones), y con la escritura pato, lo obtienes gratis.

Ahora, eso no quiere decir que su código no fallará a la mitad, si intenta llamar some_dog.quack(); obtendrá un TypeError. Francamente, si le está diciendo a los perros que graznen, tiene problemas un poco mayores; La escritura de patos funciona mejor cuando mantiene a todos sus patos en fila, por así decirlo, y no permite que los perros y los patos se mezclen a menos que los esté tratando como animales genéricos. En otras palabras, aunque la interfaz es fluida, todavía está ahí; A menudo es un error pasar un perro al código que espera que grazne y vuele en primer lugar.

Pero si está seguro de que está haciendo lo correcto, puede solucionar el problema del graznido probando la existencia de un método en particular antes de intentar usarlo. Algo como

if (typeof(someObject.quack) == "function")
{
    // This thing can quack
}

Por lo tanto, puede verificar todos los métodos que puede usar antes de usarlos. Sin embargo, la sintaxis es algo fea. Hay una forma un poco más bonita:

Object.prototype.can = function(methodName)
{
     return ((typeof this[methodName]) == "function");
};

if (someObject.can("quack"))
{
    someObject.quack();
}

Este es JavaScript estándar, por lo que debería funcionar en cualquier intérprete JS que valga la pena usar. Tiene el beneficio adicional de leer como en inglés.

Para los navegadores modernos (es decir, prácticamente cualquier navegador que no sea IE 6-8), hay incluso una forma de evitar que la propiedad aparezca en for...in:

Object.defineProperty(Object.prototype, 'can', {
    enumerable: false,
    value: function(method) {
        return (typeof this[method] === 'function');
    }
}

El problema es que los objetos IE7 no tienen .defineProperty en absoluto, y en IE8, supuestamente solo funciona en objetos host (es decir, elementos DOM y demás). Si la compatibilidad es un problema, no puede usar .defineProperty. (Ni siquiera mencionaré IE6, porque ya es bastante irrelevante fuera de China).

Otro problema es que a algunos estilos de codificación les gusta asumir que todos escriben código incorrecto y prohíben modificar Object.prototype en caso de que alguien quiera usar a ciegas for...in. Si eso le importa, o está usando (IMO roto) código que sí lo hace, pruebe con una versión ligeramente diferente:

function can(obj, methodName)
{
     return ((typeof obj[methodName]) == "function");
}

if (can(someObject, "quack"))
{
    someObject.quack();
}
close