DeepDive 19장 Prototype .part1

HunGeun·2022년 5월 1일
0

deepDive

목록 보기
1/1

JavaScript

  • JavaScript는 명령형 (imperative), 함수형 (funcional), 프로토타입 기반(prototype-based) 객체지향 프로그래밍(OOP, Object Oriented Programming)을 지원하는 멀티 패러다임 프로그래밍 언어

  • 프로토타입 기반의 JS는 클래스 기반의 객체지향 언어(C#, C++)들 보다 더욱 효율적이고 강력한 객체지향 프로그래밍 능력을 지니고 있음

  • JS에서 원시타입을 제외하고는 모두 객체임

객체지향이란

  • 원래 프로그래밍은 명령어 혹은 함수의 목록으로 보는 명령형 프로그래밍(imperative programming) 에서
    벗어나서 여러 개의 독립적 단위, 즉 객체의 집합으로 프로그램을 표현하려는 패러다임

  • 실세계에서 실체, 즉 사물이나 어떠한 개념은 특징이나 성질 같은 속성(attribute/property)을 가지고 있고, 우리는 이를 통해 실체를 인식하거나 구별 함.

  • 실세계에서 실체를 인식하는 방식을 프로그래밍에 녹여내려는 시도에서 시작함

example

사람(실체) : 이름, 주소, 성별, 나이...

여기서 특징을 구체적으로 "서울시에 사는 30세 남성" 이라고 표현하면 특정한 사람을 다른 사람과 구별하여 인식 할 수 있음.
이러한 방식을 프로그래밍에 접목 시켜서 사람에게는 무수히 많은 속성(특징)이 있지만
현재 우리(프로그램)가 필요한 속성을 간추려 내어서 표현하는 것을 abstraction(추상화) 라고 한다.

즉, 객체는 속성을 통해 여러 개의 값을 하나의 단위로 구성한 복합적인 자료구조를 말함

그리고, 이러한 객체들로 프로그램을 표현하려고 하는것이 객체지향 프로그래밍


또한, 객체안에서 객체의 상태(state)를 나타내는 데이터와
상태 데이터를 조작할 수 있는 동작을 하나의 논리적인 단위로 묶어 생각함

용어적으로는 객체의 상태를 프로퍼티(property) 라고 하고, 동작을 메서드(method)라 부른다.

또한 객체는 독립적으로 존재하지만 서로 데이터를 주고 받거나 상속하면서 관계성(relationship)를 가진다


상속(inheritance)과 프로토타입(prototype)

상속

상속이란, 어떤 객체의 프로퍼티 or 메서드를 다른 객체가 그대로 사용할 수 있는 것.
JS는 프로토타입을 기반으로 상속을 하는데, 그 과정에서 중복을 제거하고, 코드를 재사용함으로써 개발 비용을 현저히 줄일 수 있는 잠재력이 있다.

//생성자 함수
function Circle(radius) {
  this.radius = radius;
  this.getArea = function () {
    return Math.PI * this.radius ** 2;
  };
}
// 반지름 1인 원
const circle1 = new Circle(1);
// 반지름 2인 원
const circle2 = new Circle(2);

console.log(circle1.getArea === circle2.getArea) //false

Circle 생성자 함수가 생성하는 모든 객체(인스턴스)는
radius프로터티와
getArea 메서드를 갖는다.

radius 프로퍼티는 인스턴스마다 다른것이 유의미 하지만
getArea 메서드는 인스턴스마다 다른것이 무의미 하고, 메모리가 낭비됨
(만약, 10개의 인스턴스가 생성되면 getArea 메서드가 10개 생성됨)

따라서, 이러한 상황에서 상속을 통해 동일한 메서드가 불필요하게 생성되는것을 방지함.

function Circle(radius) {
    this.radius = radius;
} //radius 프로퍼티는 

Circle.prototype.getArea = function () {
  return Math.PI * this.radius ** 2;
}; //프로토타입을 기반으로 하는 상속
//Circle 생성자 함수를 통해 생성된 모든 인스턴스가 공유하며 사용가능

// 반지름 1인 원
const circle1 = new Circle(1);
// 반지름 2인 원
const circle2 = new Circle(2);

console.log(circle1.getArea === circle2.getArea) //true!!

Circle 생성자 함수 -> 인스턴스 생성 -> Circle.prototype의 모든 프로터티와 메서드를 상속받음.


프로토타입

프로토타입은 객체 간 상속을 구현하기 위해 사용됨.
어떤 객체의 상위 객체의 역할을 하는 객체임.
모든 객체는 [[Prototype]] 이라는 내부 슬롯을 가지고, 프로토타입의 참조값이 들어있음.
또한, 이 값는 객체 생성 방식에 의해 결정됨

example
리터럴에 의해 생성된 객체의 프로토타입 = Object.prototype
생성자함수에 의해 생성된 객체의 프로토타입 = 생성자함수의 prototype 프로터피에 바인딩되어 있는 객체

모든 객체는 하나의 프로토타입을 가지고, 모든 프로토타입은 생성자 함수와 연결되어 있음

  • 객체__proto__ 접근자 프로퍼티를 통해 자신의 프로토타입(=[[Prototype]] 내부 슬롯이 가리키는 프로토타입)에 간접적으로 접근 가능
  • 프로토타입자신의 constructor 프로퍼티를 통해 생성자 함수 접근
  • 생성자 함수자신의 prototype 프로퍼티를 통해 프로토타입접근
  • 접근자 프로퍼티
    접근자 프로퍼티는 자체적인 값을 갖지 않고,
    다른 데이터 프로퍼티 값을 읽거나 저장할 때 사용하는 접근자 함수(accessor function)인
    [[Get]] 과 [[Set]] 프로퍼티 어트리뷰토로 구성된 프로퍼티임.
const person = {
    firstName : 'Suzy',
    lastName : 'Bae',
  
    get fullName() {
      return `${this.firstName} ${this.lastName}`;
    },
  
    set fullname(name){
        [this.firstName, this.lastName] = name.split(' ');
    }
}

// 데이터 프로퍼티를 통한 프로퍼티 값 참조
console.log(person.firstName + ' ' + person.lastName) // Suzy Bae

// 접근자 프로퍼티를 통한 프로퍼티 값 저장
// 접근자 프로퍼티 fullName에 값을 저장하면 setter 함수가 호출된다.
person.fullName = 'Tari Kim';
console.log(person); // {firstName: "Tari", lastName: "Kim"}

// 접근자 프로퍼티를 통한 프로퍼티 값 참조
// 접근자 프로퍼티 fullName에 접근하면 getter 함수가 호출된다.
console.log(person.fullName); //Tari Kim

//데이터 프로퍼티 갖는 프로퍼티 어트리뷰트
[[Value]], [[Writable]], [[Enumerable]], [[Configurable]] 
//접근자 프로퍼티가 갖는 프로퍼티 어트리뷰트
[[Get]], [[Set]], [[Enumerable]], [[Configurable]]

내부 슬롯 관점에서 봐서, get 내부 메서드가 호출되면 다음과 같은 일련의 과정을 거친다.
1. 프로퍼티 키가 유효한지 확인함. (문자열 혹은 심볼) (키: fullName)
2. 프로토타입 체인안에서 프로퍼티를 검색함. (person객체에서 fullName 프로퍼티 발견)
3. 발견한 프로퍼티가 데이터 혹은 접근자 프로퍼티인지 판별 (접근자 프로퍼티)
4. 접근자 프로퍼티 fullName의 [[GET]]의 값인 getter 함수를 호출하고 그 값을 반환함.

+ Object.getOwnPropertyDescriptor(); 를 통해 접근자 or 데이터 프로퍼티를 구별 할 수 있음.

0개의 댓글