Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

Solucionado
(ver solução)
18
respostas

Date Referência?

Olá, estou com uma seria dúvida com relação a programação defensiva.

constructor(data, quantidade, valor){

        this._data = data;
        this._quantidade = quantidade;
        this._valor = valor;

        Object.freeze(this);
    }

Porque que quando eu crio um novo objeto de data no get, o valor da data não muda mais no get?

Eu não entendi muito bem a parte de referência.

18 respostas

Nícolas, boa tarde!

Você retorna no getter para o cliente do método uma referência a uma nova cópia do seu valor interno, se ele resolver mudar o estado da data recebida pelo seu método, ele estará alterando a cópia, e não o objeto interno da sua instância.

Ainda não entendi :s

Boa tarde, Nícolas! Como vai?

Eu não entendi a sua dúvida... Vc poderia explicar melhor para que eu possa te ajudar?

Não sei explicar bem :/.

vou tentar explicar do começo.

eu entendi que o Object.freeze() só congela as propriedades rasas, pois elas não tem algum método modificador junto a elas.

já o objeto Date(), tem seus modificadores.

e o Object.freeze() não consegue previnir isso certo?

Ai vem a programação defensiva, que eu não entendi o porque fazendo isso:

get data(){
        return new Date(this._data.getTime());
    }

retornando um novo objeto com base no objeto recebido, anula a possibilidade de alterar o valor.

não entendi essa lógica :/

Agora entendi qual é a sua dúvida!

Isso é feito pq dessa forma o seu get irá devolver uma nova instância de Date e não a instância interna do objeto que vc congelou no construtor usando o Object.freeze(). Dessa forma vc garante que o Date interno do seu objeto não será alterado!

De outra forma, se vc fizesse:

get data(){
     return this._data;
}

Vc estaria retornando o Date interno do seu objeto this! E aí quem chamasse o get teria como modificá-lo.

A ideia da cópia defensiva é simplesmente criar um clone e devolver o clone em vez do objeto original!

Pegou a ideia?

certo, porem no meu

 this._data = new Date(this.data.getTime());

eu também estou devolvendo uma nova instancia do meu objeto, e se eu fizer isso:

negociacaoModel._data.setDate(2);

a data será alterada.

Pq eu consigo alterar aqui:

this._data = new Date(this.data.getTime());

E pq não consigo aqui:

    get data(){
        return new Date(this._data.getTime());
    }
solução!

Então, o ponto é que se vc fizer negociacaoModel.data.setDate(2); o que vc vai alterar é o clone que o seu get retornou e não a data interna do seu negociacaoModel!

Tanto isso é verdade que vc pode fazer um teste assim:

var hoje = new Date();
var n1 = new Negociacao(hoje, 5, 700);
console.log(n1.data);
let clone = n1.data;
clone.setDate(2);

console.log(clone);
console.log(n1.data);

Vc verá que a data de n1 não terá sido alterado enquanto o que o clone foi alterado!

Agora, vá na sua classe Negociacao e altera o get para:

get data() {
     return this._data;
}

E execute novamente o código anterior! Vc verá que dessa vez a data de n1 será alterada pq deixamos de devolver um clone!

Vamos ver se eu entendi.

eu fiz alguns testes aqui.

Então quando eu faço o retorno de new Date(this._data.getTime()); eu estou retornando o clone? ele seria o "clone" pois se eu quiser modificá-lo, ele não está fazendo referência ao this._data -> que faz referencia a date(o parâmetro), ele está fazendo referência ao novo objeto Date, e como ele está sem referência ao objeto principal, ele não consegue modifica-lo.

Eu to meio que entendendo mas não ficou claro ainda :s

É isso mesmo, Nícolas!

Outra dúvida que me surgiu, porque conseguimos alterar ainda o nosso date, pela propriedade "privada" _data?

var n1 = new Negociacao(new Date(), 2, 100);

        console.log(n1.data);

        n1._data.setDate(19);

        console.log(n1.data);

sendo que ela recebe um novo Objeto

this._data = new Date(data.getTime());

Nícolas, cole aqui a sua classe Negociacao pra que eu possa dar uma olhada nela antes de te responder.

Classe Negociação:

class Negociacao{

    constructor(data, quantidade, valor){

        this._data = new Date(data.getTime());
        this._quantidade = quantidade;
        this._valor = valor;

        Object.freeze(this);
    }

    get data(){
        return new Date(this._data.getTime());
    }
    get quantidade(){
        return this._quantidade;
    }
    get valor(){
        return this._valor;
    }
    get volume(){
        return this._quantidade * this._valor;
    }

}

Nícolas, a resposta da sua última pergunta está nesse exercício aqui. Dá uma olhada lá e se restar alguma dúvida eu esclareço aqui!

Outra dúvida que me surgiu, porque conseguimos alterar ainda o nosso date, pela propriedade "privada" _data?

No curso você aprendeu que não existe atributos privados em JavaScript e que o uso de _ é uma convenção para indicar ao desenvolvedor que não pode acessar o atributo.

Você pode rever essa aula aqui

https://cursos.alura.com.br/course/javascript-es6-orientacao-a-objetos-parte-1/task/16500

Se ele fere essa convenção o grupo inteiro de desenvolvedores de seu time reclamará.

@Gabriel Leite

Desculpa eu tentar me explicar mais uma vez, é que eu realmente não quero ter dúvidas com relação a isso.

    get data(){
        return new Date(this._data.getTime());
    }

Esse trecho de código faz assim.

obj.data.setDate(20); aqui eu alterei a data do get, porem como toda chamada dele, ele retorna um NOVO objeto de date com base no valor da propriedade, o get sempre será o mesmo valor, por isso o nome "clone"?

@Flavio Henrique de Souza Almeida

Olá professor, eu chamo de "private" entre aspas, pq o _(underline) tem a mesma ideia(somente a ideia) de private de uma linguagem fortemente tipada.( só não faz a função dele que é privar a propriedade de ser acessada diretamente, apenas por getters e setters(se necessário)).

o _ é apenas um alerta para os programadores de que aquela propriedade/atributo, não deve ser modificada.

Gente, desculpa estender o tópico, mas senti necessidade disso.

Boa tarde, Nícolas! Respondendo suas perguntas:

obj.data.setDate(20); aqui eu alterei a data do get, porem como toda chamada dele, ele retorna um NOVO objeto de date com base no valor da propriedade, o get sempre será o mesmo valor, por isso o nome "clone"?

Isso mesmo, vc entendeu corretamente!

Olá professor, eu chamo de "private" entre aspas, pq o (underline) tem a mesma ideia(somente a ideia) de private de uma linguagem fortemente tipada.( só não faz a função dele que é privar a propriedade de ser acessada diretamente, apenas por getters e setters(se necessário)). O é apenas um alerta para os programadores de que aquela propriedade/atributo, não deve ser modificada.

Respondendo pelo Flávio, o _ (underline) é uma convenção para alertar o programador de que a propriedade não deve ser acessada diretamente e sim pelo getter ou setter. No seu caso, fazer algo como obj._data.setDate(20) seria ferir a convenção, embora seja um código válida.

Pegou a ideia?

Agora eu entendi tudo, obrigado pela paciência ^^.

e bora continuar os estudos ^^

Boa, Nícolas!

Não esquece de marcar a resposta solucionadora da sua dúvida para que o tópico fique como resolvido e outras pessoas no futuro possam encontrar a solução caso tenham a mesma dúvida!

Grande abraço e bons estudos!