본문 바로가기
Research/Computer Science

OOP in Javascript

by RIEM 2023. 4. 4.

Nam jun Paik, Li Tai Po

 

Type of programming paradigm

There are many styles of programming. Most popular styles are these:

  • imperative(명령형) programming - How
    • Procedular(절차지향) programming : focus on procedular process. C, C++, ...
    • OOP(Object-Oriented) programming : collection of objects. focus on relationships between objects. C++, Java, C#, Python, Swift, Ruby, ...
  • declarative(선언형) programming - What
    • Functional programming : focus on creating functions. Closure, Haskel, List, ...

Procedular programming is early programming style in history. It is fast and easy to debug due to its similarity between sequence of code and the order of computer process.

OOP programming is a paradigm to divide software into small components by using class or objects.

Functional programming is invented to solve spagetti code issue via function. It is regarded as no assignment statment programming style by Rober C.Martin, author of book 'CleanCode'.

OOP and JS

OOP(Object-Oriented Programming) is a programming styles focusing on classes and objects. OOP make code flexible and easy to maintain. Javascript is prototype-based procedural language, supporting both functional and object-oriented programming.

Object

Object can be created with Class.

How to design class with OOP principles.

There are 4 main principles in OOP:

  • Abstraction : hiding details and show only essential parts
  • Encapsulation : packing of data and functions into one component to controll access to that component and avoid accident manipulation from outside
  • Inheritance : resuing common logic
  • Polymorphism : having various forms

OOP in Javascript

Javascript is prototype-based language in which objects can access to properties and methods that connected to prototypes(Prototypal Inheritance). For example, arrays have push() method (Array.prototype.push()).

Way to implement prototypal inheritance in JS

  1. use constructor functions with new keyword
  2. use ES6 classes(Syntactic sugar). It works same as constructor function behind.
  3. use Object.create()

1) prototypal inheritance with Constructor Functions

Good practice

function Designer(name) {
  this.name = name;
  console.log(this)
}

// defining a function on prototype of object is good for performance
Designer.prototype.getName = function() {
  console.log(this.name)
}

let margiela = new Designer('margiela')
margiela.getName()

Bad practice

function Designer(name) {
  this.name = name;

  // Do not create function inside of a constructor function for performance
  this.getName = function() {
    console.log(this.name)
  }

  console.log(this)
}

let margiela = new Designer('margiela')
margiela.getName()
[object Object] {
  getName: function() {
    window.runnerWindow.proxyConsole.log(this.name)
  },
  name: "margiela"
}
"margiela"

If you create function directly inside constructor function, performance issue will occurs. It is because new function is created whenever instance is initiated.

Check

// Check its prototype
console.log(margiela.__proto__ === Designer.prototype) // true
console.log(Designer.prototype.isPrototypeOf(margiela)) // true

Another Practice

const items = ['Jacket', 'Pants', 'Bag', 'Bag']

Array.prototype.unique = function(){
  return [...new Set(this)]
}

console.log(items.unique())
// ["Jacket", "Pants", "Bag"]

2) prototypal inheritance with ES6 Class

There are 2 ways to create class in JS

  • Class Expression : class User = class{}
  • Clas Declaration : class User{}

3 important things about class

  • class is not hoisted
  • class is first-class citizen. It is possible to pass a function as an argument
  • class is execuated in strict mode

Setter and Getter

Setter and setter are methods to set or get a value.

class Designer{
  constructor(name){
    // (_) is convention for property of setter 
    this._name = name
  }

  get getName() {
    console.log(this._name)
  }
  set setName(newName) {
    this._name = newName
  }
}

const margiela = new Designer('margiela')
margiela.setName = 'Maison Margiela'
margiela.getName

Static methods

Static method work with only a class. In other words, you can not call the static method from the instance.

class Designer{
  constructor(name){
    this._name = name
  }

  static show() {
    console.log('fashion show started!')
  }
}

const margiela = new Designer('margiela')

margiela.show() // error
Designer.show() // "fashion show started!" - only work with class

3) prototypal inheritance with Object.create()

You can create a new object with Object.create() static method. You need existing object for this.

const Designer = {
  init(name){
    this.name = name
  },
  printName() {
    console.log(this.name)
  }
}

// const margiela = new Designer('margiela')
const margiela = Object.create(Designer)
margiela.init('margiela')
margiela.printName()

Inheritance in JS

With class inheritance, a class/object can inherit all the methods and properties from another class. This is good for reusability.

implement inheritance with ES6 syntax

class Designer {
  constructor(name, foundationYear) {
    this.name = name
    this.foundationYear = foundationYear
  }

  printName() {
    console.log(this.name)
  }
}

class FashionDesigner extends Designer {
  constructor(name, foundationYear, gender) {
    // super for passing arguments to parent class
    super(name, foundationYear)
    this.gender = gender
  }

  Stats() {
    console.log("Stats")
  }
}

const margiela = new FashionDesigner("margiela", 1979, "Unisex")
margiela.printName() // "margiela"

If you want, you can override the parent method by implementing same a method in the child class.

How to encapsulate in JS

Protected properties

Protected property can be expressed like _this.name for convention. We are not supposed to manipulate this property.

class Designer {
  constructor(name, foundationYear) {
    this._name = name
    this._foundationYear = foundationYear
  }

  get getName() {
    console.log(this._name)
  }
}

const margiela = new Designer('margiela', 1979)
// console.log(margiela._name) <- don't do this
margiela.getName // "margiela"

Private properties

You can implement truly private property by using #.

class Designer {
  #name

  constructor(name, foundationYear) {
    this.#name = name
    this._foundationYear = foundationYear
  }

  #printName() {
    console.log(this.#name)
  }

  PrintFromPrivateMethod(){
      this.#printName()
  }
}

const margiela = new Designer('margiela', 1979)
margiela.PrintFromPrivateMethod() // "margiela"
// console.log(margiela.#name) // "SyntaxError: Private field '#name' must be declared in an enclosing class

'Research > Computer Science' 카테고리의 다른 글

JWT  (0) 2023.04.06
parallel computing  (0) 2023.04.06
ISO, TCP-UDP, TCP 3way handshake  (0) 2023.03.31
List, Set, Map, HashMap  (0) 2023.03.30
Parameter와 Argument의 차이  (0) 2023.03.30

댓글