Solucionado (ver solução)
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!