Class: 제로베이스
Created: December 21, 2022 5:45 AM
Type: Javascript
강의 명: 초심자도 빈틈없이 학습하는 자바스크립트
프로토타입은 여러개 봤지만 처음봤을때 이거 보고 이해 바로했다.아래 명강의부터 먼저 요약해볼게요.
https://www.youtube.com/watch?v=wUgmzvExL_E
자바스크립트의 객체는 명세서에서 명명한
[[Prototype]]
이라는 숨김 프로퍼티를 갖습니다. 이 숨김 프로퍼티 값은null
이거나 다른 객체에 대한 참조가 되는데, 다른 객체를 참조하는 경우 참조 대상을 '프로토타입(prototype)'이라 부릅니다.’
객체에는 자동으로 이렇게 프로토타입이라는 공간이 생긴다.
유전자라고 생각하면 편하다.
생성자함수 또는 객체. prototype. name = ‘kim’ 이렇게 프로토타입을 추가할 수 있다.
이렇게 부모요소(생성자함수)에 추가해 놓으면, 프로토타입이라는 유전자에 기록이 되고, 이 생성자함수를 사용하는 모든 인스턴스, 즉 자식요소들은 이 유전자를 가져다 쓸 수 있다.
function Animal(이름) {
this.name = '이름';
this.legs = 4;
this.eat = true;
}
let rabbit = new Animal("흰 토끼");
Animal.prototype.live = true; // 부모요소에 프로토타입 추가
// rabbit.__proto__.live = true; => 이렇게 자식요소에 직접 추가할 수 있음
console.log(rabbit) // Animal { name: '이름', legs: 4, eat: true }
console.log(Animal.prototype) // { live: true }
console.log(rabbit.live) // true
배열자료형 같은걸 다룰 때, 우리는 아무렇지도 않게 기본 메소드인 length( ), sort( ) 함수를 기본적으로 사용할 수 있다. 우리가 직접 배열에 sort 나 length 같은 함수 추가해준 적 없는데, 어떻게 가능한걸까?
let arr1 = [4,3,2]
let arr2 = new Array(5,4,3)
암튼 우리는 Array에 sort 함수 추가해준적 없는데 사용할 수 있는 이유는, sort와 같은 기본 함수들이 부모요소(Array)에 기록이 되어있기 때문인 것.
let arr2 = new Array(5,4,3)
console.log(Array.prototype)
// 출력 값
[constructor: ƒ, at: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, …]
at: ƒ at()
concat: ƒ concat()
constructor: ƒ Array()
copyWithin: ƒ copyWithin()
entries: ƒ entries()
.
.
.
includes: ƒ includes()
indexOf: ƒ indexOf()
join: ƒ join()
keys: ƒ keys()
lastIndexOf: ƒ lastIndexOf()
length: 0
// ...등등
[[Prototype]]: Object
Array. prototype을 출력해보면 다음과 같이 Array라는 부모요소가 기본적으로 가지고있는 여러가지 유전자, 즉 프로토타입을 볼 수 있다.
따라서 Array로 만들어진 Array의 자식요소들은 모두 위 함수를 사용할 수 있는 것이다.
우리가 직접 만든 함수는 prototype에는 공통된 암시적으로 생성된 함수들이 없다.
Info라는 함수는 자바스크립트 내 기본적으로 들어있는 생성자함수가 아니기 때문에, 암시적으로 프로토타입이 만들어지지 않기 때문에, 명시적으로 직접 생성해줘야 함.
이렇게 공통적으로 사용되는 함수에 대해서는, 이런식으로 각각에 객체 내 메모리를 할당해서 메소드를 정의하는 것이 아닌, 밖으로 빼서 프로토타입으로 만들어서 메모리를 공유하도록 만드는 것이 메모리 효율에 좋다.
function Info(name, age) {
this.name = name;
this.age = age;
this.func = function() {
console.log(this.name, this.age)
}
}
Info.prototype.write = function() {
console.log(`이름은 ${this.name}, 나이는 ${this.age}입니다.`)
}
let info1 = new Info('Kody', 25)
let info2 = new Info('James', 30)
let info3 = new Info('Elena', 22)
console.log(info1) // Info { name: 'Kody', age: 25, func: [Function (anonymous)] }
console.log(info2) // Info { name: 'James', age: 30, func: [Function (anonymous)] }
console.log(info3) // Info { name: 'Elena', age: 22, func: [Function (anonymous)] }
내가 만약에 Array를 사용하며, 특정한 기능을 구현하는 배열의 함수를 만들었다. 근데 그걸 너무 자주 사용하다보니, 어디 저장해두고 계속 가져다가 쓰려고한다. 그럼 내가 만든 함수를 모든 Array에서 가져다쓸 수 있도록 prototype으로 추가할 수도있을 것이다.
Array.prototype.내가만든함수 = function(){} //
console.log(arr1.내가만든함수()) // undefined
위와같이 모든 Array에서 사용할 수 있도록 프로토타입에 내가만든함수를 추가할 수 있다.
개발자가 특별히 할당하지 않더라도 모든 함수는 기본적으로 "prototype"
프로퍼티 갖는다.
디폴트 프로퍼티 "prototype"
은 constructor
프로퍼티 하나만 있는 객체를 가리키는데, 여기서 constructor
프로퍼티는 함수 자신.
function Rabbit() {}
// 함수를 만들기만 해도 디폴트 프로퍼티인 prototype이 설정.
// Rabbit.prototype = { constructor: Rabbit }
console.log( Rabbit.prototype.constructor == Rabbit ); // true
constructor
프로퍼티는 기존에 있던 객체의 constructor
를 사용해 새로운 객체를 만들때 사용할 수 있다.
function Rabbit(name) {
this.name = name;
alert(name);
}
let rabbit = new Rabbit("흰 토끼");
let rabbit2 = new rabbit.constructor("검정 토끼");
이 방법은 객체가 있는데 이 객체를 만들 때 어떤 생성자가 사용되었는지 알 수 없는 경우(객체가 서드 파티 라이브러리에서 온 경우 등) 유용.
"constructor"
를 이야기 할 때 가장 중요한 점은 자바스크립트는 알맞는"constructor"
값을 보장하지 않는다는 점.
함수엔 기본으로 "prototype"
이 설정된다라는 사실 그게 전부입니다. "constructor"
와 관련해서 벌어지는 모든 일은 전적으로 개발자에게 달려있다.
함수에 기본으로 설정되는 "prototype"
프로퍼티 값을 다른 객체로 바꾸면, new를 이용해 객체를 만들었지만 객체에 “constructor”가 없는걸 볼 수 있다.
function Rabbit() {}
Rabbit.prototype = {
jumps: true
};
let rabbit = new Rabbit();
alert(rabbit.constructor === Rabbit); // false
이런 상황을 방지하고 constructor
의 기본 성질을 제대로 활용하려면 "prototype"
에 뭔가를 하고 싶을 때 "prototype"
전체를 덮어쓰지 말고 디폴트 "prototype"
에 원하는 프로퍼티를 추가, 제거해야 함.
function Rabbit() {}
// Rabbit.prototype 전체를 덮어쓰지 말고
// 원하는 프로퍼티가 있으면 그냥 추가됨.
Rabbit.prototype.jumps = true
// 이렇게 하면 디폴트 프로퍼티 Rabbit.prototype.constructor가 유지.
같은 생성자로부터 생성된 객체들은 프로토타입을 공유한다.
상위 프로토타입 속성 및 메소드를 공유하는 것을 말한다.
function Info(name, age) {
this.name = name;
this.age = age;
}
Info.prototype.write = function() {
console.log(`이름은 ${this.name}, 나이는 ${this.age}입니다.`)
}
let info1 = new Info('Kody', 25)
let parent1 = info1.__proto__;
console.log(parent1); // { write: [Function (anonymous)] }
let parent2 = parent1.__proto__;
console.log(parent2); // [Object: null prototype] {}
let parent3 = parent2.__proto__;
console.log(parent3); // null