Object Oriented Programming
-
Objects in JavaScript
- 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.
- 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.
- 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.
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:
Modo 02
var harvey = Object.create(personProto,
{
name: { value: 'Harvey' },
yearOfBirth: { value: 1972 },
job: { value: 'Lawyer' },
});
console.log(harvey);
//irá retornar: - 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.
Object-Oriented Paradigm