Em JavaScript você não precisa inicializar e nem declarar os atributos de uma classe pois é uma linguagem com tipagem dinâmica.
Aquele this.camposPublicos da classe Serializador será avaliado de acordo com o contexto (this) durante a execução do método filtrarObjeto. Como esse método só deve ser invocado pelos filhos de Serializador, o this. será uma referência ao objeto que é uma instância desse filho (por exemplo, uma instância da classe SerializadorFornecedor). Logo, this.camposPublicos em Serializador será o valor de this.camposPublicos inicializado em SerializadorFornecedor
Então, na prática, não existe isso de "y só pertence à classe x". É você quem estabelece um comportamento e interação entre os objetos. O instrutor aplicou, praticamente, o design pattern Strategy para criar os serializadores.
Se você criar uma instância de Serializador e invocar o filtrarObjeto, como this.camposPublicos nunca foi inicializado (ou seja, this.camposPublicos nesse contexto será undefined), o seguinte erro será lançado: TypeError: Cannot read property 'forEach' of undefined
Pode testar este codigo aí:
class Serializador {
constructor(contentType) {
this.contentType = contentType;
}
filtrarObjeto(dados) {
const novoObjeto = {};
this.camposPublicos.forEach((campo) => {
if (dados.hasOwnProperty(campo)) {
novoObjeto[campo] = dados[campo];
}
});
return novoObjeto;
}
}
const serializador = new Serializador()
serializador.filtrarObjeto({})
Sobre não passar o camposPublicos, faz sentido já que a classe Serializador não deveria conhecer o valor desse atributo pois o método que usa ele só será invocado por instâncias que conhecem (e inicializaram) ele em seu constructor. Como a lógica do método filtrarObjeto é genérica (dependendo apenas da definiçao de um camposPublicos), ele poderá ser reusada por todos os serializadores.
Note que em javascript há várias outras formas de obter esse mesmo comportamento que o instrutor quis ao organizar as classes assim.