"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Implementando métodos de Ruby Método em JavaScript

Implementando métodos de Ruby Método em JavaScript

Publicado em 2024-08-21
Navegar:281

Implementing Ruby

De repente, o método de métodos do Ruby não é útil? Ao escrever código, ele lista todos os métodos e propriedades disponíveis para um objeto e permite pesquisá-los, o que é muito útil para depuração.

Além disso, também é eficaz para verificar métodos específicos de frameworks como Rails, auxiliando na leitura de código e no entendimento de bibliotecas. Embora seja uma boa prática consultar a documentação oficial ou o código-fonte, o método de métodos é bastante útil para bibliotecas onde você não precisa se aprofundar ou quando tem vagas lembranças de nomes de métodos.

Métodos de Ruby Método

Para apresentar brevemente o método de métodos do Ruby, fica assim:

Objeto#método

Retorna uma lista de nomes de métodos públicos e protegidos de obj. Isso incluirá todos os métodos acessíveis nos ancestrais do obj. Se o parâmetro opcional for falso, ele retornará uma matriz de métodos singleton públicos e protegidos do obj, a matriz não incluirá métodos em módulos incluídos em obj.

Em outras palavras, ele retorna um objeto array das propriedades e métodos acessíveis a partir do receptor.

Este método é implementado na classe Object, que é o ancestral de todas as classes que herdam de Object, portanto pode ser usado em qualquer classe que herde de Object.

Código de amostra

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 mostrado no exemplo, ele retorna um objeto Array, então você também pode pesquisar na lista de métodos usando o método grep, o que é muito conveniente.

Então, pensei se isso poderia ser feito em JS e tentei.

Implementação

Abaixo está o código real.

O nome da classe pode ser qualquer coisa, mas vou chamá-la de PropertyFinder por enquanto.

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]
    }
}

Explicarei o código mais tarde, mas vamos começar explicando como usá-lo.

Uma vez definida a classe, você pode adicionar um método às propriedades da classe Object da seguinte forma:

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

Ao fazer isso, você pode usar o método de métodos em instâncias de classes herdadas de Object. No entanto, esteja ciente da nota de cuidado abaixo e use-a por sua própria conta e risco.

Aqui estão alguns exemplos de execuções:

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']

Introdução à segurança

*Este código não é recomendado para uso em ambientes de produção *

Adicionar propriedades a classes de nível superior por meio de patches de macaco é um antipadrão e pode levar a problemas com mudanças futuras nas especificações JS. Use-o com cuidado e por sua própria conta e risco.

Referência: Os contras do patch de macaco

Explicação do código

Agora, vamos explicar o código.

O método mais importante no PropertyFinder é o método find. Este método percorre a cadeia de protótipos de um determinado objeto, procura propriedades acessíveis e as retorna como uma lista.

Os métodos toString e grep simplesmente usam find, portanto não precisam de mais explicações.

Cadeia de protótipo

A cadeia de protótipos pode não ser familiar para alguns, mas é a herança de propriedades da classe Object.

Herança e cadeia de protótipos | MDN

Os detalhes são abordados na documentação do MDN, mas o mecanismo de herança do JavaScript é suportado pela cadeia de protótipos.

Embora nem sempre seja óbvio, quando se refere a alguma propriedade, o processo envolve:

  1. Verificando se o próprio receptor possui a propriedade.
  2. Verificando se a instância da classe pai possui a propriedade.
  3. Verificando se a propriedade existe na classe pai da instância da classe pai.

Esse processo continua na cadeia até que uma correspondência seja encontrada, que é então retornada.

O que o método find faz

Dado o exposto, o método find no PropertyFinder implementa esse mecanismo, permitindo que você obtenha uma lista de propriedades explorando recursivamente __proto__.

Aqui está a implementação que consegue isso explorando __proto__ recursivamente para obter a 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]
    }

Isso conclui a explicação do PropertyFinder.

Concluir

Isso encerra a explicação do código e o que eu tentei.

Este foi mais um exercício experimental ou lúdico, mas como envolveu algum conhecimento e técnicas, espero que você o considere útil ou inspirador para suas próprias aplicações.

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/version1/implementing-rubys-methods-method-in-javascript-p1e?1 Se houver alguma violação, entre em contato com [email protected] para excluí-la
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3