javascript - core - 프로토타입

yj k·2023년 4월 15일

javascript

목록 보기
10/18

prototype


01. inheritance(상속)


01_[[Prototype]]

const user = {
    activate : true,
    login : function () {
        console.log('로그인 되었습니다');
    }
};

const student = {
    passion : true
};

  • proto 는 [[Prototype]] 의 getter, setter

  • "student의 프로토타입은 user이다." 또는 "student는 user를 상속 받는다." 라고 표현한다.

  • 프로토타입에서 상속 받은 프로퍼티를 상속 프로퍼티라고 한다.


student.__proto__ = user;		//student의 프로토타입을 user로 설정

console.log(student.activate);
student.login();
console.log(student.passion);

  • 프로토타입 체인
const greedyStudent = {
    class : 11,
    __proto__ : student
};

console.log(greedyStudent.activate);    // user에서 상속 받은 상속 프로퍼티
console.log(greedyStudent.passion);     // student에서 상속 받은 상속 프로퍼티




02_prototype-feature(프로토타입 특징)

//객체 생성
const user = {
    id : 'user',
    login () {
        console.log(`${this.id}님 로그인 되었습니다.`);
    }
};

const student = {
	// 프로토 타입설정
    __proto__ : user
};

프로토타입은 프로퍼티를 읽을 때만 사용하며 프로퍼티 추가, 수정, 삭제 연산은 객체에 직접한다.

// student 객체에 id 프로퍼티 추가
student.id = 'user01';
// login 메소드 내의 this는 프로토타입에 영향 받지 않으며 this는 언제나 . 앞에 있는 객체를 의미한다. (student)
student.login();		
//출력: user01님 로그인 되었습니다.

for in 반복문은 상속 프로퍼티도 순회 대상에 포함 시킨다.

hasOwnProperty(key) : 상속 프로퍼티인지 확인하는 메소드

for(let key in student) {
 
    console.log(key);

    // key에 대응하는 프로퍼티가 상속 프로퍼티가 아니라 객체에 직접 구현 된 프로퍼티일 경우 true 반환
    let isOwn = student.hasOwnProperty(key);

    if(isOwn) {
        console.log(`객체 자신의 property : ${key}`);
    } else {
        console.log(`상속 property : ${key}`);
    }

}




02. function-prototype(생성자 함수 프로토타입)


01_object-contructor-prototype

new 연산자를 사용해 만든 객체는 생성자 함수의 프로토타입 정보를 사용해 [[Prototype]]을 설정한다.

new연산자를 통해 만든 인스턴스에 프로토타입을 설정할 경우
일일이 선언하지 않고, a유형의 인스턴스를 만들 때는 A를 프로토 타입으로 하도록 설정하는 방법

//객체 생성
const user = {
    activate : true,
    login () {
        console.log('로그인 되었습니다');
    }
};

function Student(name) {
    this.name = name;
}

설정 방법
.prototype 이라는 프로퍼티에 프로토타입으로 설정할 객체를 담는다.


// 여기서의 prototype은 앞에서 배운 프로토타입(__proto__)과 이름만 같을 뿐 실제로는 일반 프로퍼티이다.
Student.prototype = user;

// Function(Student).prototype은 new F를 호출할 때만 사용이 된다.
// new F를 호출할 때 만들어지는 새로운 객체의 [[Prototype]]을 할당한다.
// student.__proto__ == user
let student = new Student("홍길동");
let student2 = new Student("유관순");

console.log(student.activate);
student2.login();




02_function-prototype-and-constructor-property(함수의 디폴트 프로퍼티 프로토타입과 constructor 프로퍼티)

개발자가 특별히 할당하지 않아도 모든 함수는 기본적으로 "prototype" 프로퍼티를 갖는다.
디폴트 프로퍼티 "prototype"은 constructor 프로퍼티 하나만 있는 객체를 가리키는데, 여기서 consturctor 프로퍼티는 함수 자신을 가리킨다.


// 함수를 만들기만 해도 디폴트 프로퍼티인 prototype이 설정된다.
// Student.prototype = { constructor : Student };
function Student() {}

console.log(Student.prototype.constructor);
console.log(Student.prototype.constructor == Student);		//true


// 기본 프로토타입을 상속받는 객체 테스트
let student = new Student();    // { constructor : Student }를 상속 받음
console.log(student.constructor);
console.log(student.constructor == Student);		//true	




03. built-in-object-prototype(내장 객체 생성자 함수)

01_object-prototype

Object는 내장 객체 생성자 함수인데 이 생성자 함수의 prototype은 toString을 비롯 다양한 메소드가 구현 된 거대한 객체를 참조한다.


new Object(), {} 를 사용해 객체를 만들 때 만들어진 객체의 [[Prototype]]은 Object.prototype을 참조한다.

const obj = {};
console.log(obj.__proto__ === Object.prototype);
//true

console.log(obj.toString === obj.__proto__.toString);
//true

console.log(obj.toString === Object.prototype.toString);
//true




02_built-in-object-prototype

Function, String, Number를 비롯한 내장 객체들 역시 프로토타입에 메서드를 저장한다.
모든 내장 프로토타입 상속 트리 꼭대기에는 Object.prototype이 있어야 한다고 규정한다.

const num = new Number(100);

// num은 Number.prototype을 상속 받았는가? true
console.log(num.__proto__ === Number.prototype);

// num은 Object.prototype을 상속 받았는가? true
console.log(num.__proto__.__proto__ === Object.prototype);

// 체인 맨 위에는 null이 있다.
console.log(num.__proto__.__proto__.__proto__);

// Object.prototype에도 toString이 있지만 중복 메서드가 있는 경우 체인에서 가까운 메서드가 사용되어
// Number.prototype의 toString이 사용 된다.
console.log(num);	// [Number:100]
console.log(num.toString());	//100



내장 프로토타입 수정 가능하나 되도록 변경하지 않는다.
명세서에 새로 등록 된 기능을 쓰고 싶지만 자바스크립트 엔진에 구현되어 있지 않은 경우 정도에만 변경한다.

// 프로토타입 추가
String.prototype.hello = function () {
    console.log(`hello, ${this}`);
};

"JavaScript".hello();	//출력 : hello, JavaScript

string.prototype에 정의되어있는 메소드들이다.
여기서 방금 만든 hello()도 호출할 수 있다.




04_modern-method(프로토타입 접근 시 사용하는 모던 메소드)

프로토타입 접근 시 사용하는 모던 메소드

// 객체 생성
const user = {
    activate : true
};

Object.create(proto) : [[Prototype]] 이 proto를 참조하는 빈 객체를 만듦
const student = Object.create(user);
console.log(student.activate);

**__proto__을 사용해서 설정할 때 문제가 발생할 수 있으므로 `getPrototypeOf`, `setPrototypeOf`를 getter, setter로 사용한다.**

Object.getPrototypeOf(obj) - obj의 [[Prototype]]을 반환

getPrototypeOf(student) : 프로토타입이 무엇인지 알 수 있는 메소드

console.log(Object.getPrototypeOf(student));
console.log(Object.getPrototypeOf(student) === user);

Object.setPrototypeOf(obj, proto) - obj의 [[Prototype]]을 proto가 되도록 설정

setPrototypeOf : 프로토타입을 설정하는 메소드

Object.setPrototypeOf(student, {});
console.log(Object.getPrototypeOf(student));
console.log(Object.getPrototypeOf(student) === user);

**__proto__을 사용해서 설정할 때 발생할 수 있는 문제점** __proto__ 를 getter, setter로 직접 사용하면 키가 "__proto__" 일 때 에러가 발생하는 의도하지 않은 상황이 발생할 수 있다.
const obj = Object.create(user);
let key = "__proto__";
console.log(obj[key]);
//내장된 __proto__ 객체를 덮어쓸 수 있다.
obj[key] = { test : "새로운 객체 덮어쓰기" };
console.log(obj[key]);
console.log(obj.__proto__);

0개의 댓글