객체 지향 프로그래밍 with Javascript

Jiwon Yang·2020년 4월 25일
4
post-thumbnail

이 글은 생활코딩의 JavaScript 객체 지향 프로그래밍 - 1. 수업소개 - YouTube 수업을 참고 및 정리한 글 입니다.

0. 객체 지향 프로그래밍 (OOP)

코드가 많아지면, 관리하기 복잡해진다! 집에 옷장, 책장, 신발장이 있듯이 코드도 나눠 관리할 필요가 있다.

객체 : 서로 연관된 변수와 함수를 그룹핑하고 이름을 붙인 것

1. 객체의 기본

객체의 CRUD

  • Create : 리터럴 방식 (not 생성자 방식)
const jiwon = {
	age : 23,
	gender : ‘woman’
} // 속성   
  • Read
jiwon.age
jiwon[‘age’]
  • Update
jiwon.age = 24
  • Delete
delete jiwon.age

2. 객체와 반복문

for(key in jiwon) {
    console.log(key, jiwon[key])
} //jiwon.key 로 쓸 수 없는 이유 : . 다음에 변수가 올 수 없다!

3. 객체는 언제 쓰는가?

Math.PI
Math.random()
Math.floor(3.9)
  • 자바스크립트는 Math 라는 객체 안에 다양한 함수들을 지정해놓았다.
  • method : 객체 내에 정의된 함수
  • property : 객체 내부의 속성

4. 객체 만들어보기

// 객체 정의
var MyMath = {
    PI : Math.PI,
    random : () => {
        return Math.random();
    },
    floor : (val) => {
        return Math.floor(val);
    }
}

// 객체 호출
MyMath.PI

5. this

var jiwon = {
    first : 20,
    second : 30,
    sum : () => {
        return this.first + this.second;
    }
}

6. Constructor

1) Constructor의 필요성

var jiwon = {
    first : 20,
    second : 30,
    sum : () => {
        return this.first + this.second;
    }
}

var suhyun = {
    first : 50,
    second : 80,
    sum : () => {
        return this.first + this.second;
    }
}

비슷한 구조/종류의 두 객체를 동시에 바꿔주고 싶을 때!

var jiwon = {
    first : 20,
    second : 30,
    third: 40,
    sum : () => {
        return this.first + this.second + this.third;
    }
}

var suhyun = {
    first : 50,
    second : 80,
    third: 90,
    sum : () => {
        return this.first + this.second + this.third;
    }
}

이렇게 하나하나의 객체를 일일이 수정해야한다! (매우 귀찮..)

2) Constructor의 사례

  • var today = new Date('2019-04-10')
    : 내부적으로 2019-04-10 이라는 데이터(상태)를 가지고 있는 Date 객체가 생성되어 today 가 된다. 이때, 그 객체 내부를 우리는 당장 볼 수는 없다.

  • today.getFullYear()
    : 그 객체의 연도를 물어보는 메소드를 실행

3) Constructor 만들기

  • 생성자 함수 : 객체의 초기상태를 설정해두고, 호출 시, 앞에 new 가 붙어 객체를 생성하는 함수

  • constructor는 객체를 찍어내는 공장의 시스템으로서, 공장의 시스템을 바꾸면 생산물이 바뀌듯이 객체도 한번에 바뀐다.

  • constructor를 쓰면, 코드가 간결해지며, 재사용성이 높아진다.

// constructor 정의
function Person(first, second) {
    this.first = first;
    this.second = second;
    this.sum = () => {
        return this.first + this.second;
    }
}
// constructor 호출
var jiwon = new Person(20, 30);
var suhyun = new Person(40, 80);
jiwon.sum();

7. Prototype (원형)

자바스크립트는 prototype 기반의 언어이다!

1) Prototype의 필요성

생성자가 함수(메소드)를 가질 때, 객체를 생성할때마다(반복적으로), 내부의 메소드도 생성하기 때문에 메모리를 많이 잡아먹고, 성능이 떨어진다.

function Person(first, second) {
    this.first = first;
    this.second = second;
    this.sum = () => {
        return this.first + this.second;
    }
}

var jiwon = new Person(20, 30); // sum 함수 생성 (메모리와 성능 낭비)
jiwon.sum = function() => {
    return 'modified: ' + (this.first + this.second);
}
var suhyun = new Person(40, 80); // sum 함수 생성 (메모리와 성능 낭비)
suhyun.sum = function() => {
    return 'modified: ' + (this.first + this.second);
}

또한, 위처럼 생성자로 만들어진 객체의 메소드를 바꿀 때, 하나하나 노가다로 작업해야 되므로, 생산성도 떨어진다.

2) Prototype 활용하기

function Person(first, second) {
    this.first = first;
    this.second = second;
}
Person.prototype.sum = () => {
    return this.first + this.second;
} // Person으로 100개의 객체를 만들어도 sum 메소드는 이거 하나로 공유 

var jiwon = new Person(20, 30);
jiwon.sum = () => {
    return 'modified' + (this.first + this.second);
}
var suhyun = new Person(40, 80);
  • jiwon.sum 등 메소드가 호출될 때
    우선, 그 객체가 내부에 해당 메소드를 갖는지 확인한다.
    객체의 Prototype을 확인한다.
  • 프로토타입은 객체를 정의하는 시점이 아닌, 필요한 시점에 정의할 수 있기 때문에 메모리의 이점이 있다.
  • 프로토타입은 생성된 모든 객체가 공통으로 사용할 수 있고 재정의가 가능하기 때문에 커스터마이징도 가능하다.

8. Class

  • constructor 함수의 대체재
  • 객체를 만들어내는 공장!
class Person {
    constructor(first, second) {
        this.first = first;
        this.second = second;
    }
}
  • constructor 는 클래스가 호출되어 객체가 생성될 때, 먼저 호출되는 함수
class Person {
    constructor(first, second) {
        this.first = first;
        this.second = second;
    }
    sum() {
        return this.first + this.second;
    } // prototype과 같은 효과 (객체끼리 공유)
}

var jiwon = new Person(10, 20);
jiwon.sum = () => {
    return 'modified' + (this.first + this.second);
}
jiwon.sum(); // jiwon 내부에 sum 있는지 확인 후, class 내 메소드 확인

9. 상속의 기초

1) 상속의 필요성

  • 남의 라이브러리를 갖다 쓰는데, 메소드를 추가하고 싶을 때
  • 기존 클래스를 유지하고 싶으면서, 다른 메소드를 추가로 갖는 클래스가 필요할 때

2) 상속의 활용

class Person {
    constructor(first, second) {
        this.first = first;
        this.second = second;
    }
    sum() {
        return this.first + this.second;
    }
}

class PersonPlus extends Person {
    avg() {
        return (this.first + this.second)/2;
    }
}
  • 중복제거를 통해 효율적으로 코드 작성 가능하다.
  • 부모 클래스만 바꾸어도 자식클래스까지 동시다발적으로 바꿀 수 있어 효율적이다.

3) 상속의 문제점

  • 자식클래스에서 부모클래스의 속성과 기능에 추가적인 무언가를 넣어 활용할때 다시 부모클래스의 코드를 사용해야하는 중복이 발생할 것이다.

ex) 자식클래스에 third 라는 속성을 추가하고 싶다면

  class Person {
    constructor(first, second) {
        this.first = first;
        this.second = second;
    }
    sum() {
        return this.first + this.second;
    }
  }
  
  class PersonPlus extends Person {
    constructor(first, second, third) {
        this.first = first;
        this.second = second;
        this.third = third;
    }
    sum() {
        return this.first + this.second  + this.third;
    }
    avg() {
        return (this.first + this.second)/2;
    }
  }

// 안 돌아가는 코드

4) 해결책 : super

  • super에 괄호가 있으면 부모클래스의 생성자
  • super에 괄호가 없으면 부모클래스 자체
class Person {
    constructor(first, second) {
        this.first = first;
        this.second = second;
    }
    sum() {
        return this.first + this.second;
    }
}

class PersonPlus extends Person {
    constructor(first, second, third) {
        suepr(first, second, third)
        this.third = third;
    }
    sum() {
        return super.sum() + this.third;
    }
    avg() {
        return (this.first + this.second)/2;
    }
}

10. 자바스크립트에서의 ‘상속’

  • class : 객체를 만들어내는 공장
  • object : class를 통해 만들어진 것

1) Object Inheritance

  • 주류 객체 지향 언어(ex.java) 에서의 상속
    : super class의 상속을 받은 sub classobject 를 생성한다.

  • javascript 에서의 상속
    : super objectsub object 를 상속하는 등 특정 객체가 다른 객체의 상속을 받을 수 있다!
    그리고, 우리는 얼마든지 이 상속 관계를 바꿀 수 있다!
    상속 관계를 바꿀때는 prototype link만 바꿔주면 된다
    * 이것이 바로 자바스크립트가 prototype base langauge 라고도 불리는 이유다!

2) __proto__

  • __proto__ 를 통해서 prototype link를 걸 수 있다!
  • 즉, 객체 사이에 상속 관계를 만들 수 있다.
var superObj = { superVal : 'super' }
var subObj = { subVal : 'sub' }
subObj.__proto__ = superObj;
console.log(subObj.subVal); // sub
console.log(subObj.superVal); // super
  • 객체.속성 : 해당 객체가 그 속성을 찾고, 없으면, (__proto__로 연결된) 그 객체의 부모 객체에서 속성을 찾는다.
subObj.superVal = 'sub';
console.log(subObj.superVal); // sub
console.log(superObj.superVal); // super
  • 자식 객체에서 속성을 바꾸는 것은 부모 객체에 영향을 주지 않는다.
  • __proto__ 문법은 공식적으로 표준은 아니지만, 거의 표준이다.

3) Object.create()

  • Object.create() 를 통해서도 prototype link를 걸 수 있다!
var superObj = { superVal : 'super' }
var subObj = Object.create(superObj);
subObj.subVal = 'sub';
  • Object.create() 문법은 공식적으로 표준 이다.

자바스크립트 디버거 기능 참고
JavaScript 객체 지향 프로그래밍 - 13.3. Object.create() - YouTube

4) 객체 상속의 활용

  • __proto__ 활용방식
var jiwon = {
    first : 10,
    second : 20,
    sum : () => {
        return this.first + this.second;
    }
}
var suhyun = {
    first : 50,
    second : 100,
    avg : () => {
        return (this.first + this.second)/2
    }
}
suhyun.__proto__ = jiwon

console.log(suhyun.sum()) // 150
console.log(suhyun.avg()) // 75
  • Object.create() 활용방식
var jiwon = {
    first : 10,
    second : 20,
    sum : () => {
        return this.first + this.second;
    }
}
var suhyun = Object.create(jiwon);
suhyun.first = 50;
suhyun.second = 100;
suhyun.avg = () => { return (this.first + this.second)/2 };

console.log(suhyun.sum()) // 150
console.log(suhyun.avg()) // 75
  • prototype link를 활용하여 런타임 와중에 상속관계를 언제든지 바꿀 수 있다!

11. call

  • 함수도 객체다!
  • 모든 함수는 call 이라는 메소드를 갖는다.
  • call : 첫번째 인자에 원하는 객체를 전달하면, 실행되는 함수의 this값을 원하는 객체로 바꿔서 실행할 수 있게 해준다!
var jiwon = { first : 10, second : 20}
sum(prefix) {
		// sum.call(jiwon) 으로 인해 this = jiwon 이 됨!
    return prefix + (this.first + this.second);
}
console.log(sum.call(jiwon, ‘hi’));
  • 호출할 함수.call(this가 가리키는 객체, args …)

12. bind

  • bind : 실행되는 함수의 this값을 원하는 객체로 고정시키는 새로운 함수를 만들어낸다.
var jiwon = { first : 10, second : 20}
sum(prefix) {
    return prefix + (this.first + this.second);
}
var jiwonSum = sum.bind(jiwon, ‘->’);
console.log(jiwonSum());

13. prototype VS proto

  • 함수는 객체다.
  • 그러므로, 함수는 프로퍼티를 가질 수 있다.
// 1번
function Person(){}
// 2번
var Person = new Function();
  • 구조

Person 생성자를 만들면, Person 내에 prototype 이라는 프로퍼티가 생성되고, Person’s prototype(== Person.prototype) 을 만들어서 가리킨다. 그리고 이것은 constructorPerson 을 가리킨다. (상호참조)

Person 으로 kim과 lee 객체를 만든다면, 이것들의 __proto__ 라는 프로퍼티는 Person’s prototype 를 가리키게 된다.

kim.sum() 을 호출한다면, 우선, kim 내부를 확인하고, 없다면, __proto__ 가 가리키는 곳, 즉, Person’s prototype 의 내부를 확인한다.

14. 생성자 함수를 통한 상속

방법 1 - 객체가 객체를 상속
방법 2 - Class 로 상속 (선호!)

1) 생성자 함수로의 상속 VS 클래스로의 상속

2) constructor 를 확인하는 방법

  • 주류 객체 지향에서 인스턴스의 class 를 확인하려는 것과 비슷함
  • kim.constructor 를 찾으면, kim 내부에 없기 때문에, __proto__ 가 가리키는 Person’s prototypeconstructor 를 찾는다. 그런데, 이 constructor 는 바로 Person 을 가리킨다.

profile
안녕하세요 양지원입니다

0개의 댓글