객체지향 프로그래밍 | JavaScript Intermediate

Wonkook Lee·2021년 7월 29일
0
post-thumbnail
post-custom-banner

Object-Oriented Programming?

Definition

  • Object-oriented programming is a programming paradigm based on the concept of objects;
  • We use objects to model(describe) real-world or abstract features;
  • Objects may contain data (properties) and code(methods). By using objects, we pack data and the corresponding behavior into one block
  • In OOP, object are building blocks of applications, and interact with one another;
  • Interactions happen through a public interface (API): methods that the code outside of the object can access and use to communicate with the object;
  • OOP was developed with the goal of organizing code, to make it more flexible and easier to maintain (avoid "spaghetti code").

Classes and Instance (Traditional OOP)

Class

  • Like a blueprint from which we can create new objects.
  • JavaScript does NOT support real classes like other languages.

Instance

  • New object created from the class. Like a real house created from an abstract blueprint.

"How do we actually design classes? How do we model real-world data into classes?"

4 Fundamental Principles for Good Class Implementation

These principles can also be used outside of OOP, but they are especially relevant in this context.

1. Abstraction

Ignoring or hiding details that don't matter, allowing us to get an overview perspective of the thing we're implementing, instead of messing with details that don't really matter to our implementation.

Do we really need to know all the things inside of iPhone? NO! We can use iPhone even we don't know at all behind the scenes.

2. Encapsulation

Keeping properties and methods private inside the class, so they are not accessible from outside the class. Some methods can be exposed as a public interface(API).

Why do we need encapsulation?

Prevents external code from accidentally manipulating internal properties/state.

Allows to change internal implementation without the risk of breaking external code.

3. Inheritance

Making all properties and methods of a certain class available to a child class, forming a hierarchical relationship between classes. This allows us to reuse common logic and to model real-world relationships.

The goal of this is to reuse logic that is common to both of the classes.

4. Polymorphism

A child classes can overwrite a method it inherited from a parent class (it's more complex than that, but enough for our purpose.)

OOP in JavaScript

JavaScript also has an OOP paradigm which objects are instantiated from a class, which functions like a blueprint.

Prototypes

  • Objects are linked to a prototype object;
  • Prototypal inheritance: The prototype contains methods (behavior) that are accessible to all objects linked to that prototype;
  • Behavior is delegated to the linked prototype object.

3 Ways of Implementing Prototypal Inheritance in JavaScript

"How do we actually create prototypes? And how do we link objects to prototypes? How can we create new objects, without having classes?

1. Constructor functions

  • Technique to create objects from a function;
  • This is how built-in objects like Arrays, Maps or Sets are actually implemented.
/***********************************************************
Inheritance Between "Classes": Constructor Functions
************************************************************/

// Real class do not exist in JS
// How do we set up the prototype chain between constructor functions

const Person = function (firstName, birthYear) {
  this.firstName = firstName;
  this.birthYear = birthYear;
};

Person.prototype.calcAge = function() {
  console.log(2021 - this.birthYear);
};

// Parent Constructor와 같은 인자를 가지지만 추가할 수도 있다
// ParentConstructor.call(this, arguments...)로 부모의 프로퍼티를 가져온다
const Student = function (firstName, birthYear, course) {
  // new Operator를 사용하지 않으면 Regular Function Call이 됨
  Person.call(this, firstName, birthYear);
  this.course = course;
};

// Linking prototype
// Create connection manually using Object.create()
Student.prototype = Object.create(Person.prototype);
// Student.prototype에는 기본적으로 빈 객체가 있으며
// 이곳에 Person.prototype을 할당해 주는 과정이 prototype chain을 만든다

// 이게 안되는 이유?
// 우리는 Student가 prototype chain으로서 Person에 종속, 프로퍼티를 상속하길 원하지
// Parent prototype 자체를 원하는 것은 아니기 때문이다.
// Student.prototype = Person.prototype;

Student.prototype.introduce = function() {
  console.log(`My name is ${this.firstName} and I study ${this.course}`);
};

const wonkook = new Student('Wonkook', 2020, 'Computer Science');
console.log(wonkook);

wonkook.introduce();

// Student prootype의 constructor가 Person으로 되어있다
// 이것을 고쳐야 할 때가 있다
console.dir(Student.prototype.constructor);

// Inspection - prototype chain이 잘 셋업됨
console.log(wonkook instanceof Student);
// Expected Output: true
console.log(wonkook instanceof Person);
// Expected Output: true
console.log(wonkook instanceof Object);
// Expected Output: true

Student.prototype.constructor = Student;
// 바뀌었다
console.dir(Student.prototype.constructor);

2. ES6 Classes

  • Modern alternative to constructor function syntax;
  • "Syntactic sugar": behind the scene, ES6 classes work exactly like constructor functions;
  • ES6 classes do NOT behave like classes in "classical OOP"
/***********************************************************
217. Inheritance Between "Classes": ES6 Classes
************************************************************/

class PersonCl {
  constructor(fullName, birthYear) {
    this.fullName = fullName;
    this.birthYear = birthYear;
  }
  
  // Instance methods
  calcAge() {
    console.log(2021 - this.birthYear);
  }

  get age() {
    return 2021 - this.birthYear;
  }

  set fullName(name) {
    if (name.includes(' ')) this._fullName = name
    else console.log(`${name} is not a full name!`);
  }

  get fullName() {
    console.log(this.fullName);
  }

  // Static method
  static hey() {
    console.log(`Hey there 👋🏻`);
  }
};

// extends + super(...arguments)
class StudentCl extends PersonCl {
  constructor(fullName, birthYear, course) {
    // super는 항상 제일 먼저 호출되어야 한다!
    super(fullName, birthYear);
    this.course = course;
  }

  introduce() {
    console.log(`My name is ${this._fullName} and I study ${this.course}`);
  }
};

const wonkookCl = new StudentCl('Wonkook Lee', 1999, 'Computer Science');

console.log(wonkookCl);
// Expected Output: StudentCl {_fullName: "Wonkook Lee", birthYear: 1999, course: "Computer Science"}

wonkookCl.introduce();
// Expected Output: "My name is Wonkook Lee and I study Computer Science"

// Overwrite parents's (inheritanced) method
StudentCl.prototype.calcAge = function () {
  console.log(`I'm ${2021 - this.birthYear} years old, but as a student I feel more like ${2031 - this.birthYear}`);
}

wonkookCl.calcAge();
// Expected Output: "I'm 22 years old, but as a student I feel more like 32"

3. Object.create()

  • The easiest and most straightforward way of linking an object to a prototype object.
profile
© 가치 지향 프론트엔드 개발자
post-custom-banner

0개의 댓글