///////
Search

프로토타입 (1)

자바스크립트는 프로토타입 기반 언어이다.
클래스 기반 - 상속 사용
프로토타입 기반 - 원형을 삼고 이를 복제

프로토타입 개념 이해

1. constructor, prototype, instance

흐름 이해하기
어떤 생성자 함수 (Constructor)를 new 연산자와 함께 호출하면
Constructor에서 정의된 내용을 바탕으로 새로운 instance가 생성
instance는 __proto__ 라는 프로퍼티가 자동 부여
이 프로퍼티는 Constructor의 prototype 프로퍼티를 참조
var Person = function (name) { this._name = name; }; Person.prototype.getName = function () { return this._name; };
JavaScript
복사
→ Person의 인스턴스는 __proto__ 프로퍼티를 통해 getName 호출이 가능하다.
var suzi = new Person('suzi'); suzi.__proto__.getName(); // undefined // 왜 undefined? // this가 suzi.__proto__를 가리킨다. (메서드로 호출됐을 때의 this) Person.prototype === suzi.__proto__ // true
JavaScript
복사
getName 의 결과가 undefined 일까?
→ this 바인딩 대상이 잘못 지정되었다.
var suzi = new Person('suzi'); suzi.__proto__._name = 'suzi__proto__'; suzi.__proto__.getName(); // suzi__proto__
JavaScript
복사
this를 suzi.__proto__ 가 아닌 인스턴스로 하는 방법은 무엇일까?
__proto__ 없이 인스턴스에서 곧바로 메서드를 사용하기
var suzi = new Person('suzi', 28); suzi.getName(); // suzi var iu = new Person('jieun', 28); iu.getName(); // jieun
JavaScript
복사
__proto__생략 가능한 프로퍼티
자바스크립트는 함수에 자동으로 객체인 prototype 프로퍼티를 생성
해당 함수를 생성자 함수로 사용할 경우 → 인스턴스에 숨겨진 프로퍼티인 __proto__ 자동 생성
__proto__ 프로퍼티는 생성자 함수의 prototype 프로퍼티 참조
__proto__ 프로퍼티는 생략 가능하기 때문에 인스턴스는 생성자 함수의 prototype 의 메서드, 프로퍼티를 자신의 것처럼 접근 가능
var arr = [1, 2]; console.dir(arr); console.dir(Array);
JavaScript
복사
__proto__ 에 Array의 메서드들이 들어있다.
프로토타입 메서드 vs 정적 메서드
프로토타입 메서드 → 인스턴스가 마치 자신의 메서드처럼 호출할 수 있다.
정적 메서드 → 인스턴스가 직접 호출이 불가능하다. 생성자 함수에서 직접 접근해야한다.

2. constructor 프로퍼티

constructor 프로퍼티는 원래의 생성자 함수(자기 자신)를 참조
인스턴스로부터 그 원형이 무엇인지를 알 수 있는 수단
var arr = [1, 2]; Array.prototype.constructor = Array // true arr.__proto__.constructor === Array // true arr.constructor === Array // true var arr2 = new arr.constructor(3, 4); console.log(arr2); // [3, 4]
JavaScript
복사
constructor는 읽기 전용 속성이 부여된 예외적인 경우를 제외하고는 값을 바꿀 수 있다.
→ 참조하는 대상이 바뀔 뿐, 인스턴스의 원형이 바뀌지는 않는다.
// 다음은 모두 같은 대상을 가리킨다. [Constructor] [instance].__proto__.constructor [instance].constructor Object.getPrototypeOf([instance]).constructor [Constructor].prototype.constructor
JavaScript
복사

프로토타입 체인

1. 메서드 오버라이드

정리 - prototype 개체를 참조하는 __proto__ 를 생략하면 인스턴스를 prototype 에 정의된 프로퍼티나 메서드를 자신의 것처럼 사용가능
Q: 인스턴스가 동일한 프로퍼티나 메서드를 가지고 있는 상황이라면?
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()); // 바로 지금
JavaScript
복사
메서드 오버라이드 → 메서드 위에 메서드를 덮어씌운것
자신의 프로퍼니 검색 → __proto__ 검색
console.log(iu.__proto__.getName()); // undefined // -> Person의 prototype 객체에는 name 프로퍼티가 없기 때문 Person.prototype.name = '이지금'; console.log(iu.__proto__.getName()); // 이지금 // this가 prototype을 바라보고 있다 -> call, apply 사용 console.log(iu.__proto__.getName.call(iu)); // 지금
JavaScript
복사
결론 → 오버라이드된 경우에도 __proto__ 의 메서드에 우회적으로 접근이 가능하다.

2. 프로토타입 체인

모든 객체의 __proto__ 에는 Object.prototype 이 연결
프로토타입 체인
어떤 데이터의 __proto__ 프로퍼티 내부에 다시 __proto__ 프로퍼티가 연쇄적으로 이어진 것
프로토타입 체이닝
프로토타입 체인을 따라가며 검색하는 것
var arr = [1, 2]; Array.prototype.toString.call(arr); // 1, 2 Object.prototype.toString.call(arr); // [object Array] arr.toString(); // 1, 2 (__proto__ 생략) arr.toString = function () { return this.join('_')l }; arr.toString(); // 1_2 -> 메서드 오버라이딩 (자신의 메서드가 적용)
JavaScript
복사
arr.__proto__Array.prototype 을 참조
Array.prototype.__proto__Object.prototype 을 참

3. 객체 전용 메서드의 예외사항

어떤 생성자 함수이든 prototype 은 반드시 객체
Object.prototype 이 언제나 프로토타입 최상단에 존재
Object.prototype 의 메서드는 다른 데이터 타입도 사용할 수 있다.
객체만을 대상으로 동작하는 객체 전용 메서드는?
→ 정적 메서드로 부여
Object.prototype 에 접근할 수 없는 객체
Object.create(null)__proto__ 가 없는 객체를 생성

4. 다중 프로토타입 체인

대각선의 __proto__ 를 연결해주면 된다.
__proto__ 가 가리키는 대상인 생성자 함수의 prototype 이 연결하고자 하는 상위 생성자 함수의 인스턴스를 바라보게 한다.
var Grade = function () { var args = Array.prototype.slice.call(arguments); for (var i = 0; i < args.length; i++) { this[i] = args[i]; } this.length = args.length; }; var g = new Grade(100, 80);
JavaScript
복사
call apply 대신 배열 메서드를 직접 사용하게 하려면?
g.__proto__ , Grade.prototype 이 배열의 인스턴스를 바라보게 한다.
Grade.prototype = [];
JavaScript
복사