prototype

Andy·2023년 8월 25일
0

자바스크립트

목록 보기
12/39

❗️자바스크립트는 클래스라는 개념이 없다. 그래서 기존의 객체를 복사하여 새로운 객체를 생성하는 프로토타입 기반의 언어이다.

prototype이라는 프로퍼티와 proto라는 프로퍼티가 새로 등장했는데, 이 둘의 관계가 프로토타입 개념의 핵심이다.❗️prototype은 객체이다. 이를 참조하는 proto 역시 당연히 객체이다. 이를 참조하는 proto역시 당연히 객체이다. prototype 객체 내부에는 인스턴스가 사용할 메서드를 저장합니다. 그러면 인스턴스에서도 숨겨진 프로퍼티인 proto를 통해 이 메서드들에 접근할 수 있게 됩니다.

var Person = function(name){
    this._name= name;
};
Person.prototype.getName=function(){
    return this._name;
}
//이제 person의 인스턴스는 __proto__ 프로퍼티를 통해 getName을 호출할수 있음

var andy = new Person("andy");
console.log(andy.__proto__.getName()); //undefined
console.log(Person.prototype===andy.__proto__); //true

❗️여기서 집중해야할 부분은 undefined로 출력되는것이다. 문제는 this에 바인딩된 대상이다. 위의 코드에서 andy.proto.getName() 에서 getName 함수 내부에서의 this는 andy가 아니라 andy.proto라는 객체가 되는것. 이 객체 내부에는 name프로퍼티가 없으므로 '찾고자 하는 식별자가 정의대 있을 않을 때는 error대신 undefined를 반환한다.

andy.__proto__._name="andy";
console.log(andy.__proto__.getName()); //andy

위와 같이 proto 객체에 name프로퍼티가 있으면 출력이 가능하다.❗️그러니까 관건은 this이다. this를 인스턴스로 할수 있게 하는방법으로 proto없이 인스턴스에서 곧바로 메서드를 쓰는것.

var tom = new Person("tom");
console.log(tom.getName()); //tom

❗️proto는 생략 가능한 프로퍼티이다.

andy.__proto__.getName
-> andy(.__proto__).getName
-> andy.getName

개발자 도구에서 확인해보았다

var Constructor = function(name){
    this.name= name;
}
Constructor.prototype.method1=function(){
};
Constructor.prototype.property1='Constructor Prototype Property';

var instance = new Constructor('instance');

console.dir(Constructor);
console.dir(instance);


❗️instace의 디렉터리 구조가 constructor의 디렉터리 구조와 비교해 보았을 때 constructor prototype과 동일한 내용으로 구성돼 있다.

var arr=[1,2];
arr.forEach(function(){}) // 출력 가능
console.log(Array.isArray(arr))//true
arr.isArray(); //typeError

위와 같이 Array의 prototype 프로퍼티 내부에 있지 않은 from, isArray 등의 메서드들은 인스턴스가 직접 호출할 수 없음으로 이들은 Array 생성자 함수에서 직접 접근해야 실행이 가능하다.

constructor 프로퍼티

생성자 함수의 프로퍼티인 prototype 객체 내부에는 constructor라는 프로퍼티가 있습니다. 인스턴스의 proto객체 내부에도 마찬가지입니다. 이 프로퍼티는 단어 그대로 원래의 생성자 함수(자기 자신)을 참조한다.

var arr=[1,2];
console.log(Array.prototype.constructor===Array); //true
console.log(arr.constructor===Array); //true
console.log(arr.__proto__.constructor===Array);//true

var arr2= new arr.constructor(3,4);
var arr3= new arr.__proto__.constructor(4,5);
console.log(arr2); //[3,4]
console.log(arr3); //[4,5]
var Person = function(name){
    this.name = name;
};
var p1 = new Person('사람1');
var p1proto = Object.getPrototypeOf(p1);
var p2= new Person.prototype.constructor('사람2');
var p3= new p1proto.constructor('사람3');
var p4 = new p1.__proto__.constructor('사람4');
var p5 = new p1.constructor('사람5');

[p1,p2,p3,p4,p5].forEach(function(p){
    console.log(p,p instanceof Person);
})
/*
Person { name: '사람1' } true
Person { name: '사람2' } true
Person { name: '사람3' } true
Person { name: '사람4' } true
Person { name: '사람5' } true
*/

p1부터 p5 까지는 모두 person의 인스턴스이다.

//다음 각 줄은 모두 동일한 대상을 가리킨다.
[Constructor]
[instance].__proto__.constructor
[instance].constructor
Object.getPrototypeOf([instacne]).constructor
[Constructor].prototype.constructor
//다음 각 줄은 모두 동일한 객체(prototype)에 접근할 수 있다.
[Constructor].prototype
[instance].__proto__
[instance]
Object.getPrototypeOf([instance])

메서드 오버라이드

//메서드 오버라이드
var Person = function(name){
    this. name = name;
}
Person.prototype.getName= function(){
    return this.name;
};

var iu = new Person('지금');
iu.getName =function(){
    return '바로' + this.name;
};
console.log(iu.getName()); //바로 지금

여기서 일어난 현상을 메서드 오버라이드라고 한다. 메서드 위에 메서드를 덮어씌웠다는 표현이다. 원본을 제거하고 다른 대상으로 교체하는 것이 아니라 원본이 그대로 있는 상태에서 다른 대상을 그 위에 얹는 것.
❗️자바스크립트 엔진이 getName 이라는 메서드를 찾는 방식은 가장 가까운 대상인 자신의 프로퍼티를 검색하고, 없으면 그다음으로 가까운 대상인 proto를 검색하는 순서로 진행한다.
그렇다면 메서드 오버라이딩이 이뤄져 있는 상황에서 prototype에 있는 메서드에 접근하는 방법은 아래와 같다.

Person.prototype.name='이 지금';
console.log(iu.__proto__.getName()); //이 지금
console.log(iu.__proto__.getName.call(iu)); //지금

프로토타입 체인

객체의 내부 구조

배열의 내부 구조

위의 그림과 같이 객체의 내부구조는 proto와 동일한 내용으로 이뤄져 있다.이러한 이유는 바로 prototype객체가 '객체'이기 때문이다. 기본적으로 모든 객체의 proto에는 Object.prototype이 연결된다.

//배열에서 배열 메서드 및 객체 메서드 실행
var arr=[1,2];
arr(.__proto__).push(3) // .__proto__ 생략 가능
arr(.__proto__)(.__proto__).hasOwnProperty(2)//true

❗️어떤 데이터의 proto프로퍼티 내부에 다시 proto프로퍼티가 연쇄적으로 이어진것을 프로토타입 체인이라 하고, 이 체인을 따라가며 검색하는 것을 프로토타입 체이닝이라고 한다.

//메서드 오버라이드와 프로토타입 체이닝
var arr= [1,2];
console.log(Array.prototype.toString.call(arr)); //1,2 출력
console.log(Object.prototype.toString.call(arr)); //[object Array] 출력

arr변수는 배열이므로 arr.proto는 Array.prototype을 참조하고, Array.prototype은 객체이므로 Array.prototype.proto는 Object.prototype을 참조할 것.

profile
열정으로 가득 찬 개발자 꿈나무 입니다

0개의 댓글