Object.getPrototypeOf()
(ES5), Object.setPrototypeOf
(ES6) 메소드를 사용해 접근)**[[Prototype]] =** proto or null (프로토타입 체인의 종결점인 Object.prototype의 **[[Prototype]]** 경우)
Function.prototype
을 가리킨다.Function.prototype
이 된다.prototype 프로퍼티
생성자 함수는 본인이 생성하는 인스턴스들의 [[Prototype]]인 prototype 프로퍼티를 갖는다.
다만 축약형 함수나 화살표 함수의 경우 생성자 함수로 사용할 수 없으므로(constructor 가 없음) prototype 프로퍼티를 갖지 않는다.
function Person(name, gender) {
this.name = name;
this.gender = gender;
this.sayHello = function () {
console.log("Hi! my name is " + this.name);
};
}
var arrowFunc = () => {
return "arrow";
};
var foo = new Person("Lee", "male");
console.dir(Person);
console.dir(foo);
console.log(foo.__proto__ === Person.prototype); // ① true
console.log(Person.prototype.__proto__ === Object.prototype); // ② true
console.log(Person.prototype.constructor === Person); // ③ true
console.log(Person.__proto__ === Function.prototype); // ④ true
console.log(Function.prototype.__proto__ === Object.prototype); // ⑤ true
console.log(arrowFunc.prototype); // undefined
함수 리터럴이나 객체 리터럴(function
)으로 생성되는 객체들 역시 모두 Object(), Function() 생성자로 생성되는 객체이기 때문에 Object.prototype, Function.prototype 을 [[Prototype]]으로 둔다.
var person = {
name: "Lee",
gender: "male",
sayHello: function () {
console.log("Hi! my name is " + this.name);
},
};
console.dir(person);
console.log(person.__proto__ === Object.prototype); // ① true
console.log(Object.prototype.constructor === Object); // ② true
console.log(Object.__proto__ === Function.prototype); // ③ true
console.log(Function.prototype.__proto__ === Object.prototype); // ④ true
prototype 객체는 constructor 프로퍼티를 갖는다. 이 constructor 프로퍼티는 객체의 입장에서 자신을 생성한 객체(생성자 함수)를 가리킨다.
function Person(name) {
this.name = name;
}
var foo = new Person("Lee");
// Person() 생성자 함수에 의해 생성된 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(Person.prototype.constructor === Person);
// foo 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(foo.constructor === Person);
// Person() 생성자 함수를 생성한 객체는 Function() 생성자 함수이다.
console.log(Person.constructor === Function);
자바스크립트는 특정 객체의 프로퍼티나 메소드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티 또는 메소드가 없다면 [[Prototype]]이 가리키는 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메소드를 차례대로 검색한다. 이것을 프로토타입 체인이라 한다.
객체의 프로퍼티를 참조하는 경우, 해당 객체에 프로퍼티가 없을 경우에 프로토타입 체인이 동작하지만, 객체의 프로퍼티에 값을 할당하는 경우에는 프로토타입 체인이 동작하지 않는다.
function Person(name) {
this.name = name;
}
Person.prototype.gender = "male"; // ①
var foo = new Person("Lee");
var bar = new Person("Kim");
console.log(foo.gender); // ① 'male'
console.log(bar.gender); // ① 'male'
// 1. foo 객체에 gender 프로퍼티가 없으면 프로퍼티 동적 추가
// 2. foo 객체에 gender 프로퍼티가 있으면 해당 프로퍼티에 값 할당
foo.gender = "female"; // ②
console.log(foo.gender); // ② 'female'
console.log(bar.gender); // ① 'male'
생성자 함수로 생성할 인스턴스들의 부모가 될 prototype 프로퍼티에 모든 인스턴스가 사용할 공통적인 프로퍼티 또는 메서드를 설정해 줄 수 있다.
function Person(name) {
this.name = name;
}
var foo = new Person("Lee");
var bar = new Person("Kim");
Person.prototype.sayHello = function () {
console.log("Hi! my name is " + this.name);
};
foo.sayHello(); // Hi! my name is lee
bar.sayHello(); // Hi! my name is kim
자바스크립트에서 원시 타입들은 객체와 유사하게 동작할 때가 있다. (예: str.length)
빌트인 객체인 String, Number, Array 객체 등이 가지고 있는 표준 메소드는 프로토타입 객체인 String.prototype, Number.prototype, Array.prototype 등에 정의되어 있다.
원시 타입으로 프로퍼티나 메소드를 호출할 때 원시 타입의 빌트인 객체의 prototype으로 일시적 변환되어 프로토타입 객체를 공유하게 된다.
빌트인 객체의 prototype 프로퍼티에 추가한다면 원시 타입의 확장이 가능해진다.
var str = "test";
String.prototype.myMethod = function () {
return "myMethod";
};
console.log(str.myMethod());
console.dir(String.prototype);
console.log(str.__proto__ === String.prototype); // ① true
console.log(String.prototype.__proto__ === Object.prototype); // ② true
console.log(String.prototype.constructor === String); // ③ true
console.log(String.__proto__ === Function.prototype); // ④ true
console.log(Function.prototype.__proto__ === Object.prototype); // ⑤ true
prototype 프로퍼티를 동적으로 바꿈으로써 객체의 상속을 구현할 수 있다.
이 때 주의할 점은 프로토타입 변경 시점과 인스턴스 생성 시점에 따라 각각의 [[Prototype]]이 다르게 바인딩 된다.
function Person(name) {
this.name = name;
}
var foo = new Person("Lee");
// 프로토타입 객체의 변경
Person.prototype = { gender: "male" };
var bar = new Person("Kim");
console.log(foo.gender); // undefined
console.log(bar.gender); // 'male'
console.log(foo.constructor); // ① Person(name)
console.log(bar.constructor); // ② Object() (Object.prototype.constructor)
var x = 1; // 전역 변수 x
console.log(window.x); // 1
y = 2; // 암묵적 전역 변수 y
console.log(window.y); // 2