All Articles

wecode 2주차_4일 TIL_객체의 생성자, 프로토타입,클래스

drink-3169977_1920.jpg

커피나 홍차에 설탕이 빠질수 없듯이! 컴퓨터 세상에서도 설탕역할을 하는 달콤한 녀석들이 이다.

Syntactic sugar

우리말로 하면 문법적 설탕정도..? 어려운 컴퓨터 세상 언어를 좀 더 달콤하게, 문법적인 거부감 없이 쓸 수 있게 만들어주는 애들을 Syntactic sugar라고 한다.

오늘 우리가 알아볼 javascript의 class도 이에 속한다고 할 수 있다. 나도 동의한다… 왜냐… 나는 플라시보 효과를 믿거든 ㅜㅜ 지금 class에 대한 개념이 너무너무너무 어려우니까 설탕이라고 생각하고 달게 삼킬란다!

여튼… 클래스를 알아보기 전에 객체의 상속에 대해 먼저 알아보자!!!!

객체의 생성자

ES6문법인 class가 나오기 전에 우리는 객체의 생성자를 통해 메소드를 물려주곤 했다.

image.png(사진출처 : G마켓 http://item.gmarket.co.kr/Item?goodscode=1263969902) 광고아님ㅋㅋ 이미지가 맘에들었을 뿐 T^T

세 가지 맛 붕어빵을 만든다고 생각해보자. 객체를 만드는 과정을 세 번 반복할 수도 있지만, 우리는 생성자와 new 연산자를 이용해 좀 더 쉽고, 간단하게 같은 property를 가진 객체들을 만들어낼 수 있다! 요렇게~

function Fish_bread(flavour,mix,brand) {
    this.flavour = flavour;
    this.mix = mix;
    this.brand = brand;
}

let redbean =  new Fish_bread('redbean',{'whaet':70, 'rice': 30},'둘둘철강')
let choco = new Fish_bread('chocolate',{'wheat':80, 'rice':20},'이레철강')
let creamcheese = new Fish_bread('creamcheese', {'wheat': 65, 'rice':35},'가마니철강')
  • 생성자(constructor) : 객체를 생성할 수 있는 함수. 여기선 Fish_bread가 생성자! 생성자 안에 this.property이름이라는 property를 써서 그 값이 할당된 객체를 만든다.
  • new 연산자 : 객체의 생성, 프로토타입 설정, 객체의 초기화 과정을 통해 같은 property를 가진 새로운(new) 객체를 만든다
  • 인스턴스(instance) : new 연산자로 생성한 객체. 여기서 인스턴스는 redbean, choco, creamcheese이다.

프로토타입 상속

우리의 자바스크립트는 프로토타입 상속을 기반으로 하는 객체지향언어이다. 여기서 객체지향이란건 객체의 특성 중 하나인 재사용성이 좋다는 점을 이용하는건데! 공통적인 요소들을 새롭게 만드는 것이 아닌 부모로 부터 상속 받을 수 있도록 하고, 새로운 요소는 자식에 저장을 하는 것을 말한다.

이 말이 나는 뭔진 알겠는데 뭔지 모르겠다.. 근데 그러면 그건 걍 모르는거다! 이번 기회에 이게 무슨 뜻인가 생각하면서 정리해보기로 마음 먹었다 ㅠㅠ

dna-1889085_1920.jpg

DNA를 통해 유전정보를 상속받는 인간처럼 객체 또한 부모객체로부터 상속을 받을 수 있다. Java와 같은 객체지향 언어에서는 class를 통해 상속이 이루어진다는데, 자바스크립트에선 생성자(constructor)를 통해 상속쓰~ ES6문법에서 클래스라는 개념이 등장했지만, 우리의 js는 굳건히 프로토타입 상속을 기반으로 한다.

여튼.. ES6 클래스가 나오면서 좀 더 이 개념이 쉬워졌다는데(정말?) 일단 기존의 프로토타입 상속에 대해서 먼저 살펴보자!

let macaron_1 = {
    name : 'salted caramel',
    introduce : function() {
        return `This is ${this.name} macaron`
    }
}

let macaron_2 = {
    name : 'mint chocolate'
}

macaron_2.__proto__ = macaron_1
console.log(macaron_2)

macaron2의 콘솔을 찍어보면 macaron1에서 초기화 된 객체의 틀을 이어받아서 {name: "mint chocolate"}라는 결과값이 나오게 된다. introduce라는 값은 상속을 받긴 했지만 콘솔엔 macaron_2만 찍었기 때문에 안 나온다.

다시 콘솔창에 macaron_2.introduce()를 찍어보면 "This is mint chocolate macaron"라는 값이 나오게 된다.

이번에는 macaron_2의 유전정보를 파헤쳐보자!

image.png

__proto__ 부분을 살펴보면 macaron1 객체에 저장되어 있던 정보들을 확인해 볼 수 있다. `macaron2.introduce()`의 결과값이 나오는 과정을 좀 더 자세히 알아보자면..

  1. macaron_2에서 introduce()라는 프로퍼티를 가지고 있는지 확인해본다.
  2. macaron2에 없으니까 얘의 조상님인 macaron1으로 거슬러 올라간다.
  3. macaron_1에 introduce()가 있네? 이제 그걸 사용한다.

이런 식으로 자기가 가지고 있지 않은 프로퍼티를 __proto__정보를 보며 거슬러 올라가는 것을 프로토타입 체인이라고 한다. 우리는 객체의 연결고리를 통해 원하는 정보를 효율적으로 저장할 수 있다. 이러한 과정을 거쳐 프로토타입 상속을 객체지향 언어가 바로 우리의 친구, 자바스크립트!

function Macaron_1(amount,price) {
    this.amount = amount;
    this.price = price;
}

Macaron_1.prototype.total = function() {
    return this.amount*this.price
}

let m2 = new Macaron_1(2,2500)
console.log(m2.total()) // 5000

일반적으로 객체 생성하는 방식으로 객체를 만들어 보았다. 이걸 클래스로 바꾸어보자!

class

객체를 찍어내는 일종의 함수를 클래스라고 말한다. 사실 MDN을 봐도 class가 딱히 뭐다! 하고 시원하게 정의내려주진 않는다.. 내가 난독증이라 못 찾는건가 ㅠㅠ 그냥 super나 constructor 같은 클래스 멤버들을 쓰기 위한 틀 정도로 이해하면 될까?

class Macaron_1 {
    constructor(amount, price) {
        this.amount = amount;
        this.price = price;
    }
    total() {
        return this.amount*this.price;
    }
}

let m2 = new Macaron_1(2,2500)
console.log(m2.total())

여튼 위에서 만든 식을 이렇게 클래스로 다시 만들어도 결과값은 동일하다! 각각의 구성에 대해 자세히 살펴보자

image.png

다음 파트로 넘어가기 전, 호이스팅에 대해 잠깐 짚고 넘어가보자

함수 선언문으로 정의한 생성자는 호이스팅이 되지만, 함수 표현식, 클래스 선언문, 클래스 표현식으로 정의한 애들은 호이스팅이 되지 않는다. 이 점을 주의해야 할 것 같다. 시간 관계상 식을 따로 만들기보단, 모던 자바스크립트 입문 도서에 있는 재미없는 식을 콘솔창에 찍어 비교해봤다.

image.png

사실 클래스에선 호이스팅이 일어날수도 있다! 우리 눈에 안 보일뿐… 여튼 콘솔창에 찍으면 웹 브라우저에선 에러가 나는데.. 브라우저 문제 일수도?! 여튼.. 에러가 나니까 일단은 쓰지 말자!

class 멤버 : constructor, extends, super

클래스 멤버들을 살펴보기 전에 식을 하나 띄울거다. Anurag Majumdar님이 쓴 포스팅을 보면서 공부해봤다~

class Food {
  constructor(name, country) {
    this.name = name;
    this.country = country;
  }
  yum() {
    return `${this.name} is JMT.`
  }
  spicy() {
    return `${this.name} is spicy.`
  }
  available() {
    return `${this.name} is available now.`
  }
}

class Chicken extends Food {
  constructor(name, country) {
    super(name, country);
  }
  favorite() {
    return `${this.name} is one of my favorites.`
  }
  hanNyibMan() {
    return `Can I try this ${this.name}?`
  }
  friends() {
    return `${super.yum()} ${this.hanNyibMan()}`
  }
}

function display(content) {
  console.log(content)
}

const chicken = new Chicken('twotwochicken', 'Korea')
display(chicken.favorite())
display(chicken.friends())
  • constructor : 맨 처음에 객체의 생성자 파트에서 나왔던 그 친구, 맞다. 우리말로 하면 생성자 함수. function 역할을 대신해서 객체가 생성될 때 그 객체의 초기상태를 세팅하는 것! 객체가 만들어지기 직전에 실행되도록 약속된거라고 한다.. 말이 너무 어렵다. 걍 함수메이커라고 보자! 근데 1클래스당 1생성자다. 2개 이상 만든다면 Syntax Error가 생길 것!
  • extends : 부모 클래스와 자식 클래스를 연결해주는 ↘연↗결↘고↗리↗ 역할쓰
  • super : 부모클래스의 constructor를 호출하기 위해 필요한 애. 때론 객체로, 때론 함수로 쓰인다. 함수로 쓰일 땐, 자식 클래스에 부모 클래스가 가진 함수를 불러준다. 객체처럼 쓰일 땐,

글이 너무 길어 지는거 같기도 하고, 좀 더 알아보기 쉽게 하기 위해 위의 식을 그림으로 나타내보았다.

image.png

클래스가 더 간편한 거라고 했는데 너무 복잡하게 생겼는데요?? 라고 할 수도 있다. 구버전으로도 한번 써 보자!

Food.prototype.yum = function() {
    return `${this.name} is JMT`
}

function Chicken(name, country) {
    Food.call(this, name, country)
}

Chicken.prototype = Object.create(Food.prototype)
Chicken.prototype.constructor Chicken

이런식으로 푸드의 프로토타입은 이거고 저거고..기타 등등을 다 짚고 넘어가야 한다. 개발자들은 이런 길고 비효율적인 식을 싫어하기 때문에 클래스라는 신기술을 만들었겠쥐?ㅋㅋ

포스팅이 참 길어졌는데… 클래스에 대해서 파보려면 한도 끝도 없을 것 같아서 일단 여기서 멈추려고 한다리 ㅠㅠ 내용은 계속 추가하거나 미래의 포스팅 목록에 작성을 해봐야겠다.. 클래스를 공부하면서 깨달은 점이 있다면

아무리 피해보려고 해도 class는 도저히 못 피한다. 프론트를 가도, 빽을 가도, class를 이해하지 못하면 아무것도 할 수 없다. 꾸준히 공부하는 수밖에..!

일단 실전연습이 중요한 것 같아서 지난번에 만들었던 게임함수를 class로 다시 구현해보려고 한다. 빨리 게임을 끝내고 python 공부로 넘어가고 싶다 ㅠㅠ

다음번에 객체지향에 대해서 좀 더 심도있게 정리해보고 싶기도 하다~ 파면 팔수록 재밌는 개발세계~♬

Reference