Skip to content

Instantly share code, notes, and snippets.

@simaodeveloper
Last active November 12, 2018 02:18
Show Gist options
  • Save simaodeveloper/2e6def4daad613c4c3e6bf5545d07426 to your computer and use it in GitHub Desktop.
Save simaodeveloper/2e6def4daad613c4c3e6bf5545d07426 to your computer and use it in GitHub Desktop.
Learn OOP

Learn OOP

What's a OOP?

OOP (Oriented Object Programming) is a style of programming that's focus in objects instead of functions.

Four Pillars of OOP

Encapsulation (Encapsulamento)

Is when an Object wraps variables as properties and functions as methods.

{
  property: 'value',
  method: function() {
    console.log(this.property); // access internal property
  }
}
Abstraction (Abstração)
  • Make Simpler Interface

  • Reduce the Impact of Change

  • Side-Effect Way:

let name = 'Erik';

function setName(newName) {
  name = newName;
}

name = 'Mary';
setName('John');

console.log(name); // John
  • Abstraction Way:
let name = 'Erik';
let person = {
  name: 'Manson',
  setName(name) {
    this.name = name;
  }
};

console.log(name, person.name); // Erik, Mason

name = 'Mary'

console.log(name, person.name); // Mary, Mason
Inheritance (Herança)
  • Mechanism that allows you to eliminate redundant code.
const HTMLElement = {
  hidden: false,
  innerHTML: '<div></div>',
  click: fnClick,
  focus: fnFocus,
};

const TextBox  = Object.assing(HTMLELement, { /* new props and overrides */ });
const Select   = Object.assing(HTMLELement, { /* new props and overrides */ });
const CheckBox = Object.assing(HTMLELement, { /* new props and overrides */ });
Polymorphism (Polimorfismo)

Semantic: Poly means "Many" and morphism is "Form"

Polymorphism allows us to avoid if/else and switch case statements, for example, all these objects above should have the ability to be rendered on a page, but the way each element is rendered is different from the others, in procedural way we have to use complex statements to do that.

  • Procedural Way:
switch(...) {
  case 'select': renderSelect();
    break;
  case 'text': renderTextBox();
    break;
  case 'checkbox': renderCheckBox();
    break;
}
  • OOP Polymorphism Way:
const HTMLElement = {
  hidden: false,
  innerHTML: '<div></div>',
  click: fnClick,
  focus: fnFocus,
  render: fnRender
};

const TextBox  = Object.assing(HTMLELement, { render: function() { /* implementation TextBox Render */ } });
const Select   = Object.assing(HTMLELement, { render: function() { /* implementation Select Render */ } });
const CheckBox = Object.assing(HTMLELement, { render: function() { /* implementation CheckBox Render */ } });

function pageRender(element) {
  element.render();
}

pageRender(TextBox);
pageRender(Select);
pageRender(CheckBox);
Benefits of OOP
  • Encapsulation: Reduce complexity + Increase reusability;
  • Abstraction: Reduce complexity + Isolate impact of changes;
  • Inheritance: Eliminate redundant code;
  • Polymorphism: Refactor ugly switch/case statements;

Objects

Object Literals Sintax

Object Literals use key/values pars, where keys can be properties or methods

/*HINT
* use let if you will reassign variables
* use const if the variable is a constant
*/

const circle = {
  radius: 1,
  location: {
    x: 1,
    y: 1
  },
  draw: function() {
    console.log('draw');
  }
};

// Use dot notation to access properties/methods
circle.draw();

Factory Function

We can create multiple objects easily

function createCircle(radius) {
  return {
    radius,
    draw: function() {
      console.log('draw');
    }
  };
}

const circle = createCircle(2);

circle.radius; // 2
circle.draw();

Constructor Function

Constructor function use first letter should be uppercase as Class pattern, the Constructor too use this keyword to refers to object that is executing this piece of code, and use new keyword to instantiante a new Object.

How new keyword works
  • Create a empty object;
  • point 'this' keyword to the new empty object;
  • return object;
function Circle(radius) {
  this.radius = radius;
  this.draw = function() {
    console.log('draw');
  }
}

const circle = new Circle(2);

circle.radius; // 2
circle.draw();

Constructor Property

It is a referente to a function used to construct the object

const circle = createCircle(1);

circke.constructor; // f Object() {} 

const another = new Circle(1); // f Circle() {} 

Functions are Objects

function Circle(radius) {
  this.radius = radius;
  this.draw = function() {
    console.log('draw');
  }
}

Circle.name;
Circle.length;
Circle.constructor;
Circle.call(context, arguments);
Circle.apply(context, arguments);

// Javascript use constuctor to build the custom constructor

const Circle1 = new Function('radius', `
  this.radius = radius;
  this.draw = function() {
    console.log('draw');
  }
`);

const circle = new Circle1(2);

Value vs Reference Types

Value Types (Primitives):

  • Number
  • String
  • Boolean
  • Symbol
  • undefined
  • null

Reference Types (Objects):

  • Object
  • Function
  • Array
Primitive Type Example

Primitives are copied by their value

let x = 10;
let y = x;

x = 20;

/*  
  x -> 20
  y -> 10
*/
Reference Type Example

Objects are copied by their reference

let x = { value: 10 };
let y = x;

x.value = 20;

/*  
  x -> { value: 20 }
  y -> { value: 20 }
*/

Adding/Removing Properties

const circle = new Circle(10);

// Add property
circle.location = { x: 1 };
circle['location'] = { x: 1 };


// Access property dynamically
const propertyName = 'location';
circle[propertyName] = { x: 1 };

// Delete property

delete circle.location
delete circle['location']

Enumerating Properties

// for enumateing properties from objects use "for in loop"
const circle = new Circle(10);

for (let key in circle) {

  // show just properties
  if (typeof circle[key] !== 'function') {
    console.log(key, circle[key]); // radius, 10
  }
}

// get just the keys as an array
const keys = Object.keys(circle);
console.log(keys); // [radius, draw]

// verify if property exists into the object
if ('radius' in circle) {
  console.log('Circle has a radius.');
}

Abstraction

Hide the details and show the essentials

Private Properties and Methods
function Circle(radius) {
  this.radius = radius;
  
  let defaultLocation = { x: 0, y: 0 }; // private property
  let computeOptimumLocation = function(factor) {}; // private method
  
  this.draw = function() {
    computeOptimumLocation(0.1);
    console.log('draw');
  };
}

const circle = new Circle(10);
circle.draw();

Getters and Setters

  function Circle(radius) {
  this.radius = radius;
  
  let defaultLocation = { x: 0, y: 0 }; // private property
  
  Object.defineProperty(this, 'location', {
    get: () => defaultLocation,
    set: (value) => defaultLocation = value
  });
  
  this.draw = function() {
    console.log(this.location.x, this.location.y)
    console.log('draw');
  };
}

const circle = new Circle(10);
circle.location = { x: 10, y: 15 };
circle.draw();

Inheritance

// Base / Super / Parent
function Shape() {
  this.computeOptimumLocation = function() {};
}

// The Relation "IS-A", for example: Circle is a Shape

// Derived / Sub / Child
function Circle() {}
function Square() {}
Prototypes and Prototypical Inheritance
let x = {};
let y = {};

// x -> prototype (Object) ->  .toString();

x.toString(); // [object Object]

(Object.getPrototypeOf(x) === Object.getPrototypeOf(y)); // true
Multi-level Inheritance

Objects created by a given contructor will have the same prototype

const myArray = [];

Object.getPrototypeOf(myArray).constructor; // Array (Base)

Object.getPrototypeOf(myArray.prototype).constructor; // Object (Base)
Property Descriptors
let person = { name: 'Daniel' };
let objectBase = Object.getPrototypeOf(person);
let propertyDescriptor = Object.getOwnPropertyDescriptor(objectBase, 'toString');

console.log(propertyDescriptor);

/* Display console.log

{ 
  configurable: true, // can delete ou not
  enumerable: false, // can loop through ou not
  value: f toString(), // the property/method value
  writable: true // can be overrided ou not
}
*/

Example:

let person = { name: 'Daniel' };

Object.defineProperty(person, 'name', {
  writable: false, // can't change value
  enumarable: false, // can't iterate through this property/method
  configurable: false, // can't delete this property
});

Object.keys(person); // can't iterante -> []
person.name = 'Mary'; // can't change -> 'Daniel'
delete person.name; //can't delete -> { name: 'Daniel' } 
Constructor Prototypes

The prototype of objects is equal the Contructor prototype parent

HINT: proto property is deprecated!

const circle = new Circle;

circle.__proto__ === Circle.prototype
Prototype vs Instance Members

Instance Members

function Circle(radius) {
  this.radius = radius;
}

Prototype Members

Circle.prototype.draw = function() {
  console.log('draw');
}
Iterating Instance and Prototype Members
function Circle(radius) {
  this.radius = radius;
}

Circle.prototype.draw = function() {
  console.log('draw');
}

const circle = new Circle(2)

Object.keys(circle); // returns instance members ['radius']

for (let key in circle) console.log(key); // returns instance + prototype members -> 'radius', 'draw'

circle.hasOwnProperty('radius'); // true -> because radius it's a instance member
circle.hasOwnProperty('draw'); // false -> because radius isn't a instance member
Avoid Extending the Built-in Object

Don't modify objects you don't own!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment