2022. 7. 20. 20:48ㆍWEB/Javascript
# javascript는 prototype기반언어 이다.
- javascript의 모든 객체들이 메소드와 속성들을 상속받기위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다는의미.
- 상속되는 속성과 메소드들은 해당 객체가 아니라 prototype속성에 정의 되어 있다.
- 즉 prototype은 상속받은 멤버들이 정의되는 곳이다.(해당 객체가 복사되는것이 아닌 마치 체인을 타고 올라가며 접근하는것 처럼 '참조'하고 있음)
- 프로토타입 객체는 '__proto__ 속성으로 접근 가능한 내장 객체이고, 'prototype 속성'은 상속 시키려는 멤버들이 정의된 객체를 가리킨다.
[[Prototype]]은 __proto__로 접근이 가능하고 obj.toString은 prototype chain에 의해 obj.__proto__.constructor 처럼 찾아간다
# prototype chain
- prototype객체가 상위 prototype 객체로부터 메소드와 속성을 상속받을 수 있고 이 prototype객체 역시 상위 prototype객체에서 상속받을수 있다. 이를 prototype chain이라 부른다.
- 하위 prototype에서 특정 프로퍼티를 찾을 때 상위 prototype 프로퍼티 까지 찾는것도 prototype chain의 특징이다.
- 따라서 JavaScript는 prototype chain을 통해 상속을 구현한다.
# [[Prototype]]
- JavaScript의 모든 객체에는 숨김 프로퍼티가 존재하고 이를 '[[Prototype]]' 이라 부른다
- 다른 객체를 참조하는 경우 참조 되는 대상을 'prototype'이라 부른다.
- 만약 객체의 프로퍼티를 읽으려고 하는데 해당 프로퍼티가 존재하지 않으면 [[Prototype]]에서 프로퍼티를 찾는다. -> 프로토타입 상속 이라 부른다.
# __proto__
- [[Prototype]] 프로퍼티는 __proto__를 사용하여 값을 설정할 수 있다.
let plants = {
photosynthesis : true
}
let Rose = {
color: "red"
}
let flower = {
petal : 5,
__proto__ : Rose
}
console.log(Rose.photosynthesis) // undefined
Rose.__proto__ = plants; /* [[Prototype]]의 프로퍼티 값 할당.*/
console.log(Rose.photosynthesis) // true
- __proto__는 [[Prototype]]의 getter,setter 역할을 한다.
- Rose에 photosynthesis라는 프로퍼티가 없기 때문에 [[Prototype]]의 프로퍼티를 자동으로 탐색함.
- [[Prototype]]이 Plants객체를 참조하게 만듬
- 즉 Rose는 Plants를 상속 받는다 라고 할 수 있음. 객체지향형 프로그래밍의 상속과 비슷.
- 마찬가지로 Plants에 함수가 멤버로 있다면 Rose에서도 사용이 가능해진다.
- 근래엔 Object.getPrototypeOf , Object.setPrototypeOf를 사용한다고함.
- __proto__의 값은 객체나 null만 가능하다.
- 하위 체인에서 상위 체인의 프로퍼티를 수정할수 없다. 수정시 해당 체인의 프로퍼티가 추가되는거로 간주한다. -> getter만 가능하다는 뜻
# for...in 반복문
- 상속 프로퍼티도 순회 대상에 포함이 된다.
- hasOwnProperty(key)는 상속프로퍼티를 순회 대상에서 제외할 수 있다.
- Object.keys, Object.values 는 기본적으로 상속 프로퍼티를 제외하고 동작한다.
# 내장 객체의 프로토타입
let sampleobj = {}; alert ( sampleobj ) // [object Object]
- sampleobj = {} 는 sampleobj = new Object() 과 같다.
- new 키워드를 이용해 Object()함수로 생성자 함수를 호출하면 이 생성자 함수의 prototype은 다양한 메서드가 구현되어있는 객체인 Object의 Object.prototype을 참조한다.(위에 설명한 일반 객체를 가리키는 것과는 다름)let sampleobj = { __proto__ : Object.prototype //Object를 참조 하는게 아님 }
- sampleobj.toString()을 호출하면 Object.prototype의 프로퍼티인 toString()을 가져오게 된다.
- 배열의 경우도 new Array()로 Array.prototype을 [[Prototype]]이 참조하여 만들어진다.
- Date, Function도 위와 같다.
- 모든 객체 ( Array.prototype포함 )의 상위에는 Object.prototype이 존재하고 그 상위는 null을 가리킨다.let arr = [1, 2, 3]; arr.__proto__ === Array.prototype //true arr.__proto__.__proto__ === Object.prototype //true
# 원시값
- 원시값은 객체가 아니기때문에 실질적으로 프로퍼티가 존재하지 않는다.
- 원시값도 사용하려면 new연산자를 이용해서 할당해줘야하는데 이때는 임시 래퍼 (wrpper)객체가 생성되고, 메서드를 제공하고 난 뒤에는 사라진다.
- null 과 undefined에는 해당하는 래퍼가 존재하지 않는다. 프로토타입도 존재하지 않는다.
# 내장 prototype에 메서드 추가
- Array.prototype에 객체에 키를 추가하듯이 프로퍼티를 추가 할 수 있다.
- 이렇게 추가하면 해당 Array.prototype에 의해 생성된 배열은 추가한 프로퍼티를 사용할 수 있게 된다.
- 여러가지 충돌문제로 인해 사용을 금지시 한다.
- 필요시 "메서드 빌리기" 같은 방법을 사용할 수 있다.
let obj = { 0: "Hello", 1: "world!", length: 2, }; obj.join = Array.prototype.join; alert( obj.join(',') ); // Hello,world! Array.prototype.join = F // join함수를 F함수로 바꿔버림 -> 배열들의 join메서드들은 F함수가 실행됨 ->프로토타입체인 특성
# __proto__ 를 '지양'
- Object.create(proto, [descriptors]) – [[Prototype]]이 proto를 참조하는 빈 객체를 만듭니다. 이때 프로퍼티 설명자를 추가로 넘길 수 있습니다.
- Object.getPrototypeOf(obj) – obj의 [[Prototype]]을 반환합니다.
- Object.setPrototypeOf(obj, proto) – obj의 [[Prototype]]이 proto가 되도록 설정합니다.
let plants = {
photosynthesis : true
};
let Rose = {};
Rose.__proto__ = plants; //이 과정을
let Rose = Object.create(plants); //이렇게 바꿈.
# 함수의 prototype 프로퍼티
- 생성자 함수의 프로토타입이 객체인 경우에 new연산자를 통해 만든 객체는 생성자 함수의 프로토타입 정보를 이용해 [[Prototype]]을 설정한다
- 생성자 함수(F).prototype으로 사용될 객체를 정의
let plants = { photosynthesis : true }; function rose(name) { this.name = name; } rose.prototype = plants; // plants를 참조하는 객체를 생성 let Rose = new rose(); // Rose.__proto__ = photosynthesis
- 생성자 함수에 기본으로 세팅되는 프로퍼티(F.prototype)는 [[Prototype]]과 다릅니다. F.prototype은 new F()를 호출할 때 만들어지는 새로운 객체의 [[Prototype]]을 설정합니다.
# 함수의 디폴트 프로퍼티
- 함수가 참조할 prototype을 할당하지 않으면 기본적으로 constructor 프로퍼티 하나만 있는 객체를 가리킨다.
- constructor 프로퍼티는 함수 자기 자신을 가리킨다. 모든 함수는 기본적으로 가지고 있기 때문에 해당 함수의 생성자를 알고 싶다면 constructor를 확인해 보면 된다.
- constructor : 인스턴스가 초기화될 때 실행하는 생성자 함수.
function Rose() {} /* 디폴트 prototype Rose.prototype = { constructor: Rose }; */
- Array는 클래스다. 지금가지 써왔던 배열은 Array클래스의 인스턴스였고 Array.메소드 들은 Array클래스의 prototype에서 가져온것 이다.
- push, slice ... 은 Array.prototype에 구현되어있다
class Human {
constructor(name, age) {
this.name = name;
this.age = age;
}
sleep() {
console.log(`${this.name}은 잠에 들었습니다`);
}
}
let kimcoding = new Human('김코딩', 30);
Human.prototype.constructor === Human; // 결과는?
Human.prototype === kimcoding.__proto__; //결과는?
Human.prototype.sleep === kimcoding.sleep; //결과는?
# reference
https://ko.javascript.info/prototype-inheritance
https://ko.javascript.info/native-prototypes
https://ko.javascript.info/prototype-methods
https://ko.javascript.info/function-prototype
https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes
'WEB > Javascript' 카테고리의 다른 글
[JavaScript] 비동기 (0) | 2022.07.27 |
---|---|
[JavaScript] 객체지향의 특징과 클래스 객체 인스턴스 차이 (0) | 2022.07.22 |
[JavaScript] This, new 키워드 (0) | 2022.07.16 |
[JavaScript] Event에 관하여 (0) | 2022.07.15 |
[JavaScript] DocumentFragment 장점 (0) | 2022.07.15 |