JavaScript Estendendo Classes Embutidas
JavaScript é a base do desenvolvimento web moderno, oferecendo uma linguagem versátil e poderosa para criar experiências web dinâmicas e interativas.
Classes embutidas como Array, Map, Set e Error são classes comuns internamente, portanto você pode usar extends nelas exatamente como faria com qualquer classe que você mesmo escrevesse. A subclasse herda todos os métodos do pai e pode adicionar novos métodos, substituir comportamentos ou armazenar estado extra. Esta é uma forma elegante de construir uma coleção especializada (um array que sabe como somar a si mesmo, um map com valores padrão) ou um tipo de erro específico ao domínio — sem modificar o protótipo global, que é a alternativa mais arriscada descrita em JavaScript: Native Prototypes.
Este capítulo aborda a sintaxe básica, como os métodos embutidos retornam instâncias da sua subclasse, como Symbol.species permite controlar isso, como estender Error para tipos de erro personalizados e as ressalvas que vale conhecer antes de utilizar essa técnica. Se você não conhece extends e super, leia primeiro JavaScript: Class Inheritance.
Sintaxe e Exemplo Básico
A sintaxe é idêntica à de estender qualquer outra classe:
class CustomClass extends BuiltInClass {
// New methods and properties to extend the built-in class
}Se sua subclasse define um construtor, você deve chamar super() antes de usar this. Isso permite que a classe pai inicialize corretamente seu estado interno e estruturas nativas — para Array e Map, esse estado interno é o que faz com que funcionem.
Vamos estender a classe Array com um método que soma todos os elementos:
A instância se comporta como um array completo — indexação, length, iteração e todos os métodos de Array funcionam — além do método sum() que você adicionou.
⚠️ Nota: Ao estender Array, esteja ciente de que a propriedade length tem um comportamento especial em JavaScript. Em alguns ambientes, length pode não sincronizar automaticamente com o tamanho real do array ao usar certos métodos nativos. Teste cuidadosamente ou considere composição se o rastreamento preciso do tamanho for crítico.
Métodos Embutidos Retornam Instâncias da Sua Subclasse
Esta é a parte que torna a extensão de Array verdadeiramente poderosa: métodos como map, filter e slice que retornam um novo array retornam uma instância da sua subclasse, não um Array simples. Isso significa que o novo array ainda possui seus métodos personalizados.
Internamente, o motor decide qual construtor usar por meio de um getter estático especial chamado Symbol.species. Por padrão, Symbol.species retorna a própria subclasse, por isso o filter acima produziu um ExtendedArray.
Controlando o Tipo de Retorno com Symbol.species
Às vezes você quer o oposto: métodos como map e filter devem retornar arrays simples, enquanto new ExtendedArray(...) ainda fornece sua subclasse. Substitua Symbol.species para apontar de volta para a classe base:
Agora arr é um PowerArray com seu método isEmpty(), mas filter retorna um Array simples que não carrega mais esse método. Use isso quando sua subclasse adiciona estado em seu construtor que arrays derivados não devem herdar. Symbol.species também é respeitado por Map, Set, ArrayBuffer e Promise.
Aprimorando a Classe String
A classe String é outro objeto embutido fundamental que pode ser estendido com auxiliares adicionais de manipulação de string.
Adicionando uma Função de Inversão
⚠️ Nota: Estender String é geralmente desaconselhado devido às peculiaridades de coerção de primitivo para objeto do JavaScript, que podem causar comportamento inesperado com métodos nativos. Para manipulação de string, prefira funções utilitárias ou composição em vez de herança.
Personalizando a Classe Map
A classe Map em JavaScript representa uma coleção de itens de dados com chaves, oferecendo um meio de armazenamento de dados mais avançado e flexível em comparação com objects. Estender a classe Map nos permite introduzir comportamentos mais especializados.
Implementando um Valor Padrão
Estendendo Map para retornar um valor padrão se a chave não existir. Observe como o get substituído chama super.get(key) para acessar a busca real do Map:
Estendendo a Classe Error
Um uso comum e prático desse recurso é criar tipos de erro personalizados. Criar uma subclasse de Error fornece um erro nomeado que você pode identificar com instanceof, ao mesmo tempo em que é um Error real (portanto carrega message, stack e funciona com try...catch).
Definir this.name é importante — controla como o erro é exibido e permite distinguir seu tipo de erro de um genérico. Para um tratamento mais aprofundado, incluindo como construir uma hierarquia de classes de erro, consulte JavaScript: Custom Errors, Extending Error.
Boas Práticas e Considerações
Embora estender classes embutidas abra um universo de possibilidades, é fundamental seguir boas práticas para garantir a manutenibilidade e a compatibilidade do código.
- Evite Substituir Métodos Existentes: Estender classes embutidas adicionando novos métodos é geralmente seguro. No entanto, substituir métodos existentes pode levar a comportamentos imprevisíveis e problemas de compatibilidade.
- Use para Necessidades Específicas: Estenda classes embutidas quando houver um benefício ou necessidade clara. Evite extensões desnecessárias que possam complicar sua base de código.
- Prefira Composição ou Funções Utilitárias: No JavaScript moderno, estender classes embutidas frequentemente é desnecessário. Usar funções auxiliares ou composição geralmente oferece resultados mais limpos e previsíveis sem modificar os internos de subclasses nativas.
- Documente as Extensões Claramente: Certifique-se de que qualquer extensão de classes embutidas esteja bem documentada em sua base de código para evitar confusão entre outros desenvolvedores.
Métodos estáticos também são herdados
Quando você usa extends em uma classe embutida, a subclasse também herda os métodos estáticos do pai. Portanto, ExtendedArray.from(...) e ExtendedArray.isArray(...) estão disponíveis, e métodos de fábrica estáticos como Array.from produzem instâncias da subclasse. Isso espelha a herança de classe normal — consulte JavaScript: Static Properties and Methods para saber como os membros estáticos são herdados.
Conclusão
Estender classes embutidas é uma forma elegante de adicionar comportamento focado a objetos nativos — um array que soma, um map com valor padrão, um erro nomeado — sem modificar protótipos globais. A ideia principal a lembrar é que métodos embutidos derivados retornam instâncias da sua subclasse por padrão, e Symbol.species é o mecanismo para mudar isso. Use herança quando existir uma relação verdadeira de "é-um"; caso contrário, prefira funções utilitárias simples ou composição.