JavaScript(객체지향-1)

박정호·2022년 3월 31일
0

JS

목록 보기
7/24
post-thumbnail

Constructor(생성자)

자바스크립트로 학생 리스트를 만들려 한다. 이때 다음과 같은 코드를 하드코딩할 경우 학생이 수백명이라면 똑같이 다 작성해야 할까? 그 수고를 덜기 위해 똑같은 틀의 오브젝트를 복사해서 찍어주는 기계가 바로 constructor이다.

var 학생1 = { name : 'Kim', age : 15 };
var 학생2 = { name : 'Park', age : 15 };
...

다음과 같이 기계라는 함수안에 this(인스턴스)는 새로 생성되는 오브젝트를 뜻이고, this를 이용해서 새로 복사될 object가 가질 값을 디자인해놓으면 되겠다.
학생1이라는 변수에 new연산자(새 객체를 다른 객체와 연결하기 위한 간접적인 우회 방법)를 사용하여 새롭게 기계함수를 가져다 쓰는 것이다.

function 기계(){
  this.name = 'Kim';
  this.age = 15;
}
var 학생1 = new 기계();
var 학생2 = new 기계();

학생1과 학생2의 출력 결과

함수 또한 constructor 안에 인스턴스화 시킬 수 있다.

function 기계(){
  this.name = 'Kim';
  this.age = 15;
  this.sayHi = function(){
    console.log('안녕하세요' + this.name + ' 입니다');
  }
}
var 학생1 = new 기계();
var 학생2 = new 기계();
학생2.sayHi(); // 안녕하세요 kim 입니다.

만약 학생1, 학생2 각각의 이름과 나이를 출력하고 싶다면 각각의 파라미터값을 주면 된다.

그렇다면 학생1은 park이라는 이름과 20이라는 값을 가지고 기계에 들어가 이쁜 오브젝트형으로 만들어져서 나온다고 생각하면 되겠다.!!

unction 기계(이름,나이){
  this.name = 이름;
  this.age = 나이;
  this.sayHi = function(){
    console.log('안녕하세요' + this.name + ' 입니다');
  }
}
var 학생1 = new 기계('park',20);
var 학생2 = new 기계('Lee',10);

응용

문제) 상품마다 부가세() 라는 내부 함수를 실행하면 콘솔창에 상품가격 * 10% 만큼의 부가세금액이 출력되도록 하고 싶으면 constructor를 어떻게 수정??

function constructor(){
      this.부가세 = (a)=>{
        return a * 0.1
      }
    }
var product = new constructor();
console.log(`부가세 금액은 ${product.부가세(50000)}`);

prototype

위에서의 과정들을 보면 기계로부터 기계 안의 속성을 가져와 쓸 수 있었다. 이 것을 객체지향 용어로 상속이라고 한다. constructor이라는 부모에게서 name, age 속성들을 상속받아 생성하는 오브젝트들을 자식이라고 비유할 수 있다.

constructor(기계)를 생성하면 prototype이라는 항목이 보이지 않게 생성이 된다. prototype은 일종의 비밀 공간이라고 할 수 있는데, 부모의 유전자역할을 해준다.

prototype은 오브젝트 자료형을 다루듯이 출력할 수 있다. 만약 부모.prototype을 해주면 부모에 대한 유전자가 출력이된다.(즉, 부모가 사용할 수 있는 변수,함수 같은 기능들이 출력)

console.log(기계.prototype);

따라서, 부모의 이러한 유전자를 자식은 그대로 물려받을 수 있다. 아래의 코드를 보면 기계.prototype.gender라고 하여 gender라는 속성을 유전자에 추가하였다. 그러면 자식들은 부모의 gender속성을 사용할 수 있고, 학생1.gender를 출력하면 '남'이 출력된다.

function 기계(){
  this.name = 'Kim';
  this.age = 15;
}
기계.prototype.gender = '남';
var 학생1 = new 기계();
var 학생2 = new 기계();
console.log(학생1.gender); //'남'이 출력됩니다

참고)
- prototype에는 값을 여러개 부여할 수도 있고 함수도 집어넣을 수 있다.(object 자료처럼 다뤄주면 되겠다.)

  • prototype에 추가된 데이터들은 자식들이 직접 가지는게 아니라 부모만 가지고 있다.

prototype 작동원리

작동원리 1. 어떻게 prototype에 추가한 데이터를 자식이 자유롭게 사용이 가능한걸까?

자바스크립트는 오브젝트에서 데이터를 뽑을 때 확인하는 순서가 있다. (앞서 보았던 코드를 참고)
(1) 학생1에 직접 gender라는 값이 있는가? (자식에는 직접적인 prototype의 데이터가 X)
(2) 그럼 부모 유전자에 gender라는 값이 있는가? (기계.prototype에 gender 존재 O)
(3) 그럼 부모의 부모 유전자에 gender라는 값이 있는가? (만약 아니라면 부모의 부모의 부모...)
(4) 그럼 부모의 부모의 부모의 유전자에 .. 그게 있는가?

작동원리 2.자바스크립트 내장함수를 사용할 수 있는 이유

자바스크립트의 array, object는 사용 가능한 sort, push, toString, map, forEach 등과 내장함수들이 많다. 그럼 개발자가 직접 작성한 함수도 아니고, 어떻게 사용이 가능한걸까?

배열의 선언과 할당을 예로 들어보자.
내가 만드는 배열은 컴퓨터는 다음과 같이 인식한다. constructor의 속성을 가져다 쓰는 새로운 오브젝트 생성을 위해 new연산자가 떠오를 것이다.
그렇다면 new Array()라는 뜻은 Array(전역객체)라는 기계(부모)로 부터 새로운 오브젝트를 생성해달라는 뜻과 같다.(배열 역시 오브젝트형(하위개념))

var arr = [1,2,3]; //내가 작성한 배열 코드
var arr = new Array(1,2,3); // 컴퓨터가 받아들이는 배열 코드

만약 Array의 유전자를 확인하면, 자주 사용하는 배열메서드를 확인할 수 있다.

console.log(Array.prototype)

오브젝트 역시 Object라는 부모를 통해 자식 생성이 되는 것이다.

var obj = {name:"kim"}; //내가 작성한 배열 코드
var obj = new Object({name:"kim"}); // 컴퓨터가 받아들이는 배열 코드

prototype 특징

1. prototype은 constructor 함수에만 생성
일반적으로 만든 object, array를 만들어도 prototype이 존재하지 않는다.

Array.prototype // 존재
arr.prototype // undefined

그렇다면 일반 object를 상속하고 싶다면?
contructor함수를 생성하거나, Object.create()를 사용하거나 class 를 사용하면 된다.

2. 부모 유전자를 찾고 싶다면 __proto__를 출력

arr.__proto__ // 부모의 prototype이 출력 (= Array.prototype)

3. __proto__를 직접 등록하면 object끼리 상속기능을 구현가능

별도의 상속을 위한 과정 없이 __proto__를 이용하여 자식의 부모를 결정하는 것.

var 부모 = { name : 'Kim' };
var 자식 = {};
자식.__proto__ = 부모;
console.log(자식.name);

그럼 다음과 같은 코드에서는 a.name은 무엇을 출력할까?

function Parent(){
  this.name = 'Kim';
}
var a = new Parent();
a.__proto__.name = 'Park';
console.log(a.name)

a의 부모인 Parent함수에는 prototype에 { name : 'Park' }가 추가되는 것은 맞다. 하지만, a.name을 출력할 때는 직접 가지고 있는 { name : 'Kim' }이 우선적으로 출력된다.

주의

다음의 코드는 Student라는 생성자(부모)의 prototype에 sayHi라는 기능을 추가했다. 그리고 학생1이 새롭게 생성되 객체(자식)이 sayHi 기능을 호출하지만 '안녕 나는 kim이야'라는 원하는 답을 엊지 못한다.

function Student(이름, 나이){
  this.name = 이름;
  this.age = 나이;
}
Student.prototype.sayHi = () => {
    console.log('안녕 나는 ' + this.name + '이야');
  }
var 학생1 = new Student('Kim', 20);
학생1.sayHi(); //왜 이 코드가 제대로 안나오죠?

다음과 같이 출력된다.

이유는 arrow function 때문이다. arrow function은 외부의 this를 가져다 그대로 사용하는 성질이 있고, window객체를 기리키기 때문이다.

예를 들면, 오브젝트 안에서 일반함수로 만든 메서드와 arrow function으로 만든 메서드 안에서 this 값을 출력하면, sayHi()는 window객체를, sayHi2()는 오브젝트라는 객체를 가리켜 오브젝트의 정보를 출력한다.

var 오브젝트 = { 
  sayHi : () => { console.log(this) } ,
  sayHi2 : function(){ console.log(this) } 
}
오브젝트.sayHi();
오브젝트.sayHi2();

정리

JavaScript는 흔히 프로토타입 기반 언어(prototype-based language)라 불립니다.— 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다는 의미입니다. 프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지입니다. 이를 프로토타입 체인(prototype chain)이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간입니다.
참고: https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes

자바스크립트의 모든 객체는 프로토타입(prototype)이라는 객체를 가지고 있습니다.
모든 객체는 그들의 프로토타입으로부터 프로퍼티와 메소드를 상속받습니다.
이처럼 자바스크립트의 모든 객체는 최소한 하나 이상의 다른 객체로부터 상속을 받으며, 이때 상속되는 정보를 제공하는 객체를 프로토타입(prototype)이라고 합니다.
정확히 말하자면 상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의 prototype이라는 속성에 정의되어 있습니다.
참고: http://www.tcpschool.com/javascript/js_object_prototype

profile
기록하여 기억하고, 계획하여 실천하자. will be a FE developer (HOME버튼을 클릭하여 Notion으로 놀러오세요!)

0개의 댓글