Object Oriented Programming


    Objects in JavaScript
      img-fluid

    Object-Oriented Paradigm
    • Object-Oriented Programming
      a) Utiliza muito objects, properties e methods.
      b) Esses objects interagem uns com os outros para formarem aplicações complexas.
      c) Utilizamos objetos para estruturar o código, manter dados (var jessica = {yearOfBirth: 1969};).

    • Inheritance
      a) Person: método construtor, superclass, parent class.
      b) Athlete: uma instância, subclass, classe filha, herda os atributos da superclass Person e possui os seus próprios.
      img-fluid
      img-fluid

    • Prototype and Prototype Chains
      a) Todos os objetos em JavaScript possuem um prototype, tornando a inheritance possível.
      b) Prototype é o que armazena os métodos e propriedades dos construtores, esses ficam disponíveis para serem acessados caso as instâncias precisem. Exemplo abaixo.
      c) Caso a classe não encontre o prototype necessário, ela pode procurar no seu parent, até chegar em NULL, que significa que o prototype não existe.
      img-fluid

    • Function constructor
      1) Primeira letra sempre maiúscula.
      2) Sintaxe: var FunctionName = function(variables that we want to set in our objects instânciados)
      3) O interessante de um prototype é que podemos chamar sua execução somente no caso de querermos saber a idade da pessoa, ou por exemplo, no caso do calculateAge retornar uma idade acima de 65 anos, chamar outro prototype que irá adicionar algo ao objeto como uma informação que a pessoa deve se aposentar em breve.

      var Person = function(name, lastName, yearOfBirth, job) { //Função construtora
      this.name = name;
      this.yearOfBirth = yearOfBirth; Esses this.variable são utilizados para atribuir ao espaço de memória do objeto a informação passada, como se fosse "this.name = 'Jessica", mas nesse caso é a variable name, contendo essa informação)
      this.job = job;
      }
      ** Até aqui tudo será herdado nos futuros objetos (instâncias).

      ** O prototype a seguir estará disponível para ser acessado pelas instâncias, mas não é obrigatoriamente passado aos novos objetos (instâncias).
      ** Podem ser um método:
      Person.prototype.calculateAge = function() {
      this.age = (2019 - this.yearOfBirth); Sempre que for utilizar alguma variável do objeto, utilizar o this.variable para podermos acessar o endereço de memória da variável desse objeto.
      }; Adicionado um this.age aqui para que o resultado dessa conta seja adicionado ao objeto instanciado.
      ** Ou uma propriedade:
      Person.prototype.lastName = 'Pearson';

      var jessica = new Person('Jessica', 1969, 'Laywer');
      //Um console.log(jessica) vai trazer somente essas três informações.
      //Um console.log(jessica.lastName); vai trazer o sobrenome 'Pearson', pois ele não é obrigatoriamente inserido no objeto, mas foi herdado e pode ser acessado.
      img-fluid


      Exemplo limpo:
      var CompanyEmployees = function(name, lastName, yearOfBirth, job){
        this.name = name;
        this.lastName = lastName;
        this.yearOfBirth = yearOfBirth;
        this.job = job;
      }

      CompanyEmployees.prototype.calculateAge = function() {
        this.age = (2019 - this.yearOfBirth);
      };

      var jessica = new CompanyEmployees('Jessica', 'Pearson', 1969, 'Managing Partner');

      jessica.calculateAge();
      console.log(jessica);
      CompanyEmployees {name: "Jessica", lastName: "Pearson", yearOfBirth: 1969, job: "Managing Partner", age: 50}
      Veja que foi adicionado o age: 50.

      Funcionamento criação de instâncias de uma Função Construtora
      Sintaxe: var jessica = new Person('Jessica', 'Pearson', 1969, 'Laywer');
      1) Quando utilizamos o new, um novo objeto será criado, vazio.
      2) Depois disso, chega no Person, que chama a função e então ela é criada.
      3) Curiosidade: o new cria um objeto vazio para que o this seja apontado para esse
      objeto, e não para o global, para que possarmos utilizar os this que serão herdados ou estarão acessíveis através de prototypes.

    • Object.Create
      Cria-se um objeto que possui somente prototypes, e então podemos puxar esse objeto em novos objetos, para que já venham com os prototypes (geralmente methods).
      A diferença é que nesse caso, as propriedades serão definidas diretamente na criação do novo objeto.
      a) Não precisa começar com letra maiúscula, pois não será um object/function constructor.
      b) Primeiro define-se um objeto que irá agir como o prototype e então criamos um novo objeto baseado nesse prototype.
      c) Sintaxe: var nomeNovoObjeto = Object.create(prototypeName);

      //Objeto que contém somente prototype
      var personProto = {
        calculateAge: function() { calculateAge é o "nome da função", utilizado para chama-la.
      console.log(2019 - this.yearOfBirth);
      }
      };

      //Objetos que puxam o prototype e possuem suas propriedades.
      Modo 01
      var jessica = Object.create(personProto);
      jessica.name = 'Jessica';
      jessica.yearOfBirth = 1969;
      jessica.job = 'Lawyer';
      console.log(jessica);
      //irá retornar: img-fluid

      Modo 02
      var harvey = Object.create(personProto,
      {
        name: { value: 'Harvey' },
        yearOfBirth: { value: 1972 },
        job: { value: 'Lawyer' },
      });

      console.log(harvey);
      //irá retornar: img-fluid

    • Primivites vs Objects
      a) Variables primitivas (normais) possuem o valor dos dados armazenados nelas mesmas (copiam os valores para um novo espaço de memória).
      b) Variables declaradas como objetos somente apontam para o endereço de memória onde estão os dados do objeto (não possuindo uma cópia do objeto na variable), portanto caso o valor daquele endereço de memória mude, o dessa variável que está apontando também será alterado.

      Primitives
      var a = 23; declarado o valor de 'a'
      var b = a; copiado o valor de 'a' para novo espaço de memória
      a = 46; alterado o valor de 'a'
      console.log(a); exibido o valor do endereço de memória do 'a' = 46
      console.log(b); exibido o valor do endereço de memória de 'b' = 23, visto que 'b' copiou
      'a' quando este era 23.

      Object (pointer)
      var obj1 = { variável de objeto
      name: 'Jessica',
      age: 26 declarado valor da idade 26
      };

      var obj2 = obj1; obj2 aponta para os enredeços de memória do obj1
      obj1.age = 30; alterado o valor no endereço de memória do obj1 em 'age' para 30.

      console.log(obj1.age); exibido os valores dos endereços de memória do obj1 = Jessica, 30.
      console.log(obj2.age); exibidos os mesmos valores que o obj1, visto que o obj2 somente aponta para os prórios endereços de memória do obj1, poratnto obj2 = Jessica, 30.

      Functions
      var age = 27;
      var obj = {
      name: 'Jonas',
      city: 'Lisbon'
      };

      function change(a, b) {
      a = 30;
      b.city = 'San Francisco';
      }

      change(age, obj); executar a função de trocar a age e o obj (city)
      console.log(age); Vai ser a mesma, 27, pois vai enviar 27 do age e vai ser 27 = 30, no b vai ficar obj.city e vai dar update no dado. Se o a = 30 fosse age = 30, ia mudar para 30, porque ai seria executado uma linha dizendo exatamente que age = 30.
      console.log(obj.city);

      //Resultado: 27, San Francisco.
      //Mesmo que a função tenha tentado passar um valor para a primitive age = 27, não foi
      possível, pois essa primivite segura o valor que lhe foi dado.
      //Já no caso do objeto, foi atualizado o que estava no endereço de memória e como o
      objt.city simplesmente aponta para esse espaço de memória, ele irá trazer o resultado 'San
      Francisco'.

      //Isso mostra que quando passamos uma primitive para uma função, uma simples cópia é
      criada, então podemos trocar o 'a' com a função quantas vezes quisermos, mas ela não será alterada no global scope.
      //Já o objeto, quando passamos por uma função, não é o objeto, é a referência que aponta
      para o endereço de memória, e quando atualiazmos o que tem naquele enredeço, o objeto de fora irá simplesmente continuar apontando para esse endereço de memória, porém que agora estará com uma nova informação.