Executando verificação de segurança...
1

Só um pontinho. Nada a discordar, mas acrescentar. Quando crio uma extension method, eu sempre procuro adicionar ao global.using, então não está errado, porém acho que é de bom tom, quando vocêr quer algo que tenha comportamento nativo do Tipo(acho que entendeu), ser importado globalmente.

Quanto a prototype, não tenho muito mais informação a agregar pois conheço pouco, apenas para o que utilizei e por isso também que senti uma similaridade no comportamento que queria ter em js, que tenho em C#.

Obrigado, por agregar ao post!

Carregando publicação patrocinada...
5

senti uma similaridade no comportamento

A similaridade é apenas na forma como vc usa o método, ou seja, chamando objeto.novoMetodo(), como se o novoMetodo fosse realmente um método de objeto. Mas por baixo dos panos, o mecanismo é completamente diferente.

Em C#, vc apenas tem a impressão que o método foi criado na classe em questão. Mas é só um syntax sugar para a chamada do método estático: no seu exemplo, text.log() é automaticamente convertida para InjectString.log(text). Mas a classe string permanece inalterada, nenhum método foi realmente adicionado nela.

Por outro lado, em JavaScript, vc realmente está alterando a estrutura do objeto. O método passa a fazer parte dele, e inclusive é herdado pelos objetos filhos.

E tem que tomar cuidado ao adicionar coisas no protótipo, principalmente se vc usa for..in para iterar. Por exemplo, este código:

Array.prototype.novaFuncao = function() {
    // faz algo
};

var array = ['a', 'b'];
for (var i in array) {
    console.log(`${i} -> ${array[i]}`);
}

A saída é:

0 -> a
1 -> b
novaFuncao -> function() {
    // faz algo
}

Isso porque for..in também traz as propriedades que estão no protótipo do objeto, mas nem sempre pode ser o que vc quer ao iterar por ele. Então tem que tomar alguns cuidados para evitar o prototype pollution.


Não é exclusivo dessas linguagens

Vale lembrar que isso também existe em outras linguagens.

Por exemplo, em Ruby vc pode modificar qualquer classe:

# Supondo que UmaClasseQualquer já exista, eu posso adicionar novos métodos nela
class UmaClasseQualquer
    def novoMetodo(x)
        # faz algo
    end
end

E neste caso, vc está de fato adicionando um novo método na classe.

Inclusive, dá pra mudar até as classes mais básicas do sistema (embora não seja recomendado):

# Em Ruby, posso fazer isso.
# Assim, todas as somas entre números inteiros dará o mesmo resultado
class Integer
    def +(other)
       42
    end
end

# todas as expressões abaixo resultam em 42
puts 10 + 20
puts 2 + 2
puts 10000 + 2000000

Em Python também dá pra fazer algo similar:

class UmaClasseQualquer:
    # métodos da classe, etc

##################
# criar uma função qualquer
def func(self, param):
    print(f'novo método: {param}')

# adicioná-lo como método de uma classe já existente
UmaClasseQualquer.novoMetodo = func

x = UmaClasseQualquer()
x.novoMetodo(42) # novo método: 42

Mas diferente de Ruby, não dá para fazer com as classes nativas (como int ou str).

3

Na verdade quando a feature foi criada, a recomendação geral oficial era não colocar no System ou algo semelhante. Colocar global tende a ser pior ainda. Claro que para tudo tem exceção, mas para usar a exceção precisa dominar muito bem todas as consequências de usar isto, o que em projetos grandes pode ser um problema.

Em JS é bem tranquilo porque é uma linguagem criada para pequenos scripts. As pessoas usam para projetos maiores por escolherem a ferramenta errada porque está todo mundo usando, que é o que chamamos de "modinha".