"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > Implementación del método de métodos de Ruby en JavaScript

Implementación del método de métodos de Ruby en JavaScript

Publicado el 2024-08-21
Navegar:114

Implementing Ruby

De repente, ¿no es útil el método de métodos de Ruby? Al escribir código, enumera todos los métodos y propiedades disponibles para un objeto y le permite buscar entre ellos, lo cual es muy útil para la depuración.

Además de eso, también es efectivo para verificar métodos específicos de marcos como Rails, lo que ayuda en la lectura de código y la comprensión de bibliotecas. Si bien es una buena práctica consultar la documentación oficial o el código fuente, el método de métodos es muy útil para bibliotecas en las que no es necesario profundizar o cuando se tienen recuerdos vagos de los nombres de los métodos.

Métodos de Ruby Método

Para presentar brevemente el método de métodos de Ruby, se ve así:

Objeto#método

Devuelve una lista de los nombres de los métodos públicos y protegidos de obj. Esto incluirá todos los métodos disponibles en los antepasados ​​de obj. Si el parámetro opcional es falso, devuelve una matriz de métodos singleton públicos y protegidos de obj, la matriz no incluirá métodos en los módulos incluidos en obj.

En otras palabras, devuelve un objeto de matriz de las propiedades y métodos accesibles desde el receptor.

Este método se implementa en la clase Object, que es el antepasado de todas las clases que heredan de Object, por lo que puede usarse en cualquier clase que herede de Object.

Código de muestra

class Hoge
  attr_accessor :fuga

  def bar
    puts ''
  end
end

puts Hoge.new.methods     // => [:bar, :fuga=, :fuga, :hash, :singleton_class, :dup, ...]
puts Hoge.new.grep /fuga/ // => [:fuga=, :fuga]

Como se muestra en el ejemplo, devuelve un objeto Array, por lo que también puedes buscar en la lista de métodos usando el método grep, que es muy conveniente.

Entonces pensé si esto se podría hacer en JS y lo intenté.

Implementación

A continuación se muestra el código real.

El nombre de la clase puede ser cualquier cosa, pero por ahora la llamaré PropertyFinder.

class PropertyFinder {
    constructor(receiver) {
      this.receiver = receiver
    }

    grep(regexp, options = {}) {
      let res = []
      if (typeof regexp === 'string') {
        return this.find((name) => name.includes(regexp))
      }
      if (regexp instanceof RegExp) {
        return this.find((name) => regexp.test(name))
      }
      return []
    }

    toString() {
      return this.find(() => true)
    }

    find(detect) {
      const list = Object.getOwnPropertyNames(this.receiver).filter(it => detect(it))
      if (!this.receiver.__proto__) {
        return list
      }
      const ancestors = new PropertyFinder(this.receiver.__proto__).find(detect)
      return [...list, ...ancestors]
    }
}

Explicaré el código más adelante, pero comencemos con cómo usarlo.

Una vez definida la clase, puede agregar un método a las propiedades de la clase Objeto de la siguiente manera:

Object.prototype.methods = function () {
    return new PropertyFinder(this)
}

Al hacer esto, puede usar el método métodos en instancias de clases que heredan de Object. Sin embargo, tenga en cuenta la nota de precaución a continuación y utilícela bajo su propio riesgo.

Aquí hay algunos ejemplos de ejecuciones:

class Hoge {
  fuga() {
    console.log('fuga')
  }
}

console.log(new Object().methods().toString()) // => ['constructor', 'constructor', '__defineGetter__', '__defineSetter__', 'hasOwnProperty' ...]
console.log([].methods().toString())           // => ['length', 'length', 'constructor', 'at', 'concat', ...]
console.log(new Hoge().methods().grep(/fuga/)  // => ['fuga']

Introducción a la seguridad

*No se recomienda el uso de este código en entornos de producción *

Agregar propiedades a clases de nivel superior mediante parches de mono es un antipatrón y podría generar problemas con cambios futuros en las especificaciones de JS. Úselo con precaución y bajo su propio riesgo.

Referencia: Las desventajas del parcheo de monos

Explicación del código

Ahora pasemos a explicar el código.

El método más importante en PropertyFinder es el método de búsqueda. Este método recorre la cadena de prototipos del objeto dado, busca propiedades accesibles y las devuelve como una lista.

Los métodos toString y grep simplemente usan find, por lo que no necesitan más explicaciones.

Cadena prototipo

La cadena de prototipos puede resultar desconocida para algunos, pero es la herencia de propiedades de la clase Objeto.

La herencia y la cadena de prototipos | MDN

Los detalles se tratan en la documentación de MDN, pero el mecanismo de herencia de JavaScript es compatible con la cadena de prototipos.

Aunque no siempre es obvio, cuando se hace referencia a alguna propiedad, el proceso involucra:

  1. Comprobando si el propio receptor tiene la propiedad.
  2. Comprobando si la instancia de la clase principal tiene la propiedad.
  3. Comprobando si la propiedad existe en la clase principal de la instancia de la clase principal.

Este proceso continúa en la cadena hasta que se encuentra una coincidencia, que luego se devuelve.

Qué hace el método de búsqueda

Teniendo en cuenta lo anterior, el método de búsqueda en PropertyFinder implementa este mecanismo, permitiéndole obtener una lista de propiedades explorando recursivamente __proto__.

Aquí está la implementación que logra esto explorando __proto__ recursivamente para obtener la lista:

    find(detect) {
      const list = Object.getOwnPropertyNames(this.receiver).filter(it => detect(it))
      if (!this.receiver.__proto__) {
        return list
      }
      const ancestors = new PropertyFinder(this.receiver.__proto__).find(detect)
      return [...list, ...ancestors]
    }

Con esto concluye la explicación de PropertyFinder.

Envolver

Esto concluye la explicación del código y lo que he probado.

Este fue más bien un ejercicio experimental o lúdico, pero dado que implicó algunos conocimientos y técnicas, espero que lo encuentres útil o inspirador para tus propias aplicaciones.

Declaración de liberación Este artículo se reproduce en: https://dev.to/version1/implementing-rubys-methods-method-in-javascript-p1e?1 Si hay alguna infracción, comuníquese con [email protected] para eliminarla.
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3