[TIL] day02-1. JS 프로토타입

kcm dev blog·2021년 8월 4일
2

TIL

목록 보기
2/19
post-thumbnail

Intro. 기초부터 빡시게

일정이 매우 타이트한 날이었다. 마크다운 작성법을 몰라 마크다운 작성법부터 학습한 후에 전날 작성하지 못한 TIL을 작성하고, 추가적으로 학습해야할 심화학습 주제들이 점점 늘어가고 있기 때문이었다. (특강은 덤.. ㅋ.ㅋ)

본격적인 Javascript를 학습하기에 앞서 프로그래밍의 종류 그중 객체지향 프로그래밍에 대해 자세히 학습하고, Javascript의 작동 원리에 대해 학습하였다. 언젠가 학습이 필요하다 생각했던 분야 였기에 제대로 이해하고 소화할 생각이다.

처음 사용하는 도구들에 익숙해지고 해야할 일들을 효율적으로 이루기 위한 방법을 찾느라 많은 시간을 소비하고 있지만 차차 나아지리라 믿는다.

1. 객체지향과 프로토타입

1.1. 알아두기

객체: 현실에 있는 것을 추상화 하는 것이다. 여기서 추상이란, 사물이 지닌 여러 측면중 특정한 부분만 보는 것을 의미한다.

객체지향: 객체 위주로 설계하고 프로그래밍하는 패러다임
프로토타입: 사물의 원형, 공통된 모습

1.2. 객체지향에 대한 오해

  • 객체지향은 하나의 패러다임일 뿐이다

    C가 절차지향 언어이므로 객체지향 프로그래밍을 할 수 없다는 것은 오해일 뿐, 충분히 절자지향적인 코드 작성이 가능하다. 언어는 지향하는 것을 더 쉽게 구현할 수 있도록 도와주는 도구일 뿐이다.

  • 객체지향 방식이 절자지향 방식보다 뛰어나다

    상황에 따라 특정 방식이 더 뛰어날 때가 있을 뿐 항상 우위에 있는 방식은 없다. 다만, 일반적으로 단순한 프로그래밍의 경우 절차지향이, 복잡한 프로그래밍의 경우 객체지향이 더 유용한 경향이 있다.

1.3. 프로토타입이 왜 필요해?

javascript에도 객체는 존재한다. java, c++ 등의 객체지향 언어에 존재하는 class처럼 attribute와 method를 정의할 수 있다. 즉, 객체지향 프로그래밍을 할 수 있다는 것이다. 그럼에도 객체만 쓰면 되지 왜 프로토타입을 써야 하는가? 그 이유는 다음 코드를 보면 알 수 있다.

	function Person(name,company,move){
	this.name=name;
	this.company=company;

	this.getName=()=>{
		return this.name;
	};
	this.setName=(name)=>{
		this.anme=name;
	};
};
const kim=Person("kim","pro",1);
const lee=Person("lee","elis",2);

출력결과

Person {
  name: 'kim',
  company: 'pro',
  getName: [Function],
  setName: [Function]
}
Person {
  name: 'lee',
  company: 'elis',
  getName: [Function],
  setName: [Function]
}

일반적인 객체지향 언어라면 객체의 속성(attribute)만 메모리를 차지하고, 메소드(method)는 하나의 공통된 공간의 메모리를 사용할 것이다. 그러나 JS의 경우 각 객체별로 각자의 메소드를 가지면서 메모리 낭비를 하게 된다.

따라서 이러한 메모리 낭비를 방지하기 위해 탄생한 것이 프로토타입이다.
(다만, ES2015부터는 class를 공식적으로 지원함에 따라 프로토타입을 사용하지 않아도 프로토타입과 동일한 효과를 낼 수 있게 되었다.그러나 문법적인 양념일 뿐이며 자바스크립트는 여전히 프로토타입 기반의 언어다.)

1.4. 프로토타입 사용하기

생성

function Person(name,company,move){
    this.name=name;
    this.company=company;

    
};
Person.prototype.getName=()=>{
      return this.name;
};
Person.prototype.setName=(name)=>{
  this.anme=name;
};
const kim=Person("kim","pro",1);
const lee=Person("lee","elis",2);
출력결과
Person { name: 'kim', company: 'pro' }
Person { name: 'lee', company: 'elis' }
  • 객체만을 사용한 것과 달리 메소드는 객체의 메모리를 차지하지 않았음을 알 수 있다.
  • 메소드를 생성자 밖으로 꺼냄으로써 객체가 생성될 때마다 메소드를 반복적으로 생성하는 시간과 반복적 생성으로 인한 메모리 낭비를 최소화 할 수 있다.

상속

다음과 같은 방식으로 객체간 상속을 할 수 있다.
function Korean(name) {}
Korean.prototype = new Person();
전체코드
function Person(name) {
	this.name = name;
}
Person.prototype.getName = function () {
	return this.name || "길동";
};

function Korean(name) {}
Korean.prototype = new Person();
//상속
//내부적으로 생성된 변수는 사용할 수 없기에 파라마터로 'name'을 쓸 수 없다.

const lee = new Person("이길동");
const kim = new Korean("김길동");

console.log(lee.getName()); // 이길동
console.log(kim.getName()); // 길동

이제 자식 객체에 파라미터를 추가하여 값을 보내보자. kim이라는 상수에 Korean 이라는 객체를 생성하되 "홍길동"이라는 파라미터를 추가하여 객체를 생성하였다. 그러나 예상과 달리 "김길동"이 아닌 "길동"이 출력되었다. 왜 그럴까? 그 이유는 JS에서 객체의 경우 내부적으로 생성된 변수는 사용할 수 없기 때문이다.

그럼 어떻게 해야할까? 방법은 apply(this, arguments)를 사용하는 것이다.

function Korean(name) {
  	Person.apply(this, arguments); 
}

apply(this, arguments)를 사용하면 부모 생성자를 빌려 쓸 수 있다. 즉, 자식 객체에서 부모 객체를 호출하여 속성값을 전달할 수 있다는 의미이다. (java, c++에서의 super()와 유사하다)

this: 현재 객체, 호출하는 객체를 참조한다. 해당 예제에서는 Korean을 의미한다
arguments: 함수에 전달된 인수에 해당하는 array형태의 객체로 호출된 객체의 지정되지 않은 모든 인수에 대해 사용할 수 있다. 해당 예제에서는 Korean에 선언된 모든 변수들(name)를 의미한다

function Person(name) {
	this.name = name;
}
Person.prototype.getName = function () {
	return this.name || "길동";
};
Person.prototype.setName = function (name) {
	this.name = name;
};
function Korean(name) {
  	Person.apply(this, arguments); // 부모 생성자를 빌려 쓸수 있다
}
Korean.prototype = new Person();

const lee = new Person("이길동");
const kim = new Korean("김길동");

console.log(lee.getName()); // 이길동
console.log(kim.getName()); // 김길동
kim.setName("진짜 길동");
console.log(kim.getName()); // 진짜 길동

출력 결과에서 알 수 있듯, 자식 객체에서 전달한 파라미터를 전달하고, 부모 객체의 메소드를 활용하여 파라미터 값을 활용할 수 있다.

기존 객체 재활용
JS에서는 create()를 활용하여 기존의 객체를 재활용할 수도 있다. 정확히 말하자면 객체의 틀을 그대로 가져온다는 것으로 속성값을 전부 비운 상태의 객체를 똑같이 새로 만든다는 의미이다. 따라서 두 객체는 독립적인 관계로 서로에게 어떠한 영향도 주지 않는다.

const park=Object.create(lee);
console.log(park);//{ }
park.setName("park");
console.log(park);// {name: "park"}
console.log(lee);// {name: "lee"}

출력 결과에서 알 수 있듯 객체를 create()로 생성 뒤에 속성 값을 정의하지 않으면 어떤 값도 저장되지 않는다.

출처:
프로토타입: MDN 상속과 프로토타입,프로그래머스 강의
apply(): MDN Function.prototype.apply()
arguments: MDN arguments 객체

profile
오늘 배운건 오늘 소화하자!

0개의 댓글