자바스크립트는 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어다.
자바스크립트는 객체 기반의 프로그래밍 언어이며 자바스크립트를 이루고 있는 거의 모든것이 객체다.
객체지향 프로그래밍은 “객체의 집합으로 프로그램을 표현”하려는 프로그래밍 패러다임이다.
객체지향 프로그래밍은 실세계의 실체(사물이나 개념)를 인식하는 철학적 사고를 프로그래밍에 접목하려는 시도에서 시작한다.
객체의 상태 데이터를 프로퍼티, 동작을 메서드라 부른다.
각 객체는 독립적인 부품이면서 다른 객체와 관계성을 가질 수 있다.
상속은 객체지향 프로그래밍의 핵심 개념이다.
어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용할 수 있다.
- 상속을 통해 불필요한 중복을 제거한다. (기존의 코드를 적극적으로 재사용한다.)
// 생성자 함수
function Circle(radius) {
this.radius = radius;
}
// Circle 생성자 함수가 생성한 모든 인스턴스가 getArea 메서드를
// 공유해서 사용할 수 있도록 프로토타입에 추가한다.
// 프로토타입은 Circle 생성자 함수의 prototype 프로퍼티에 바인딩되어 있다.
Circle.prototype.getArea = function () {
return Math.PI * this.radius ** 2;
};
// 인스턴스 생성
const circle1 = new Circle(1);
const circle2 = new Circle(2);
// Circle 생성자 함수가 생성한 모든 인스턴스는 부모 객체의 역할을 하는
// 프로토타입 Circle.prototype으로부터 getArea 메서드를 상속받는다.
// 즉, Circle 생성자 함수가 생성하는 모든 인스턴스는 하나의 getArea 메서드를 공유한다.
console.log(circle1.getArea === circle2.getArea); // true
console.log(circle1.getArea()); // 3.141592653589793
console.log(circle2.getArea()); // 12.566370614359172
프로토타입 객체는 객체지향 프로그래밍의 핵심 개념인 상속을 구현하기 위해 사용된다.
어떤 객체의 상위(부모)객체의 역할을 하는 객체로서 다른 객체에 공유 프로퍼티/메서드를 제공해 공유한다.
모든 객체는 [[Prototype]]이라는 내부슬롯을 가지며, 이 내부 슬롯의 값은 프로토타입의 참조다.
[[Prototype]]
내부 슬롯에는 직접 접근할 수 없지만,__proto__
접근자 프로퍼티를 통해 자신의 프로토타입, 즉 자신의 [[Prototype]]
내부 슬롯이 가리키는 프로토타입에 간접적으로 접근할 수 있다.__proto__
접근자 프로퍼티모든 객체는 __proto__
접근자 프로퍼티를 통해 자신의 프로토타입에 간접적으로 접근할 수 있다.
__proto__
는 접근자 프로퍼티다.__proto__
접근자 프로퍼티는 상속을 통해 사용된다.proto는 객체가 직접 소유하는 프로퍼티가 아니라 “Object.prototype의 프로퍼티”다.
모든 객체는 상속을 통해 Object.proptotype.__proto__
접근자 프로퍼티를 사용할 수 있다.
const person = { name: 'Lee' };
// person 객체는 __proto__ 프로퍼티를 소유하지 않는다.
console.log(person.hasOwnProperty('__proto__')); // false
// __proto__ 프로퍼티는 모든 객체의 프로토타입 객체인 Object.prototype의 접근자 프로퍼티다.
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));
// {get: ƒ, set: ƒ, enumerable: false, configurable: true}
// 모든 객체는 Object.prototype의 접근자 프로퍼티 __proto__를 상속받아 사용할 수 있다.
console.log({}.__proto__ === Object.prototype); // true
__proto__
접근자 프로퍼티를 통해 프로토타입에 접근하는 이유__proto__
접근자 프로퍼티를 코드 내에서 직접 사용하는 것은 권장하지 않는다.__proto__
접근자 프로퍼티를 사용할 수 있는 것은 아니다.Object.getPrototpyeOf
메서드나 Object.setPrototypeOf
메서드를 사용할 것을 권장한다.non-constructor
인 화살표 함수와 ES6 메서드 축약 표현으로 정의한 메서드는 prototype
프로퍼티를 소유하지 않으며 프로토타입도 생성하지 않는다.prototype
프로퍼티와생성자 함수로 찍어낸 객체의 __proto__
접근자 프로퍼티는 동일한 프로토타입을 가리킨다.구분 | 소유 | 값 | 사용 주체 | 사용 목적 |
---|---|---|---|---|
proto 접근자 프로퍼티 | 모든 객체 | 프로토타입 참조 | 모든 객체 | 객체가 자신의 프로토타입에 접근 또는교체하기 위해 사용 |
prototype 프로퍼티 | constructor | 프로토타입 참조 | 생성자 함수 | 생성자 함수가 자신이 생성할 객체(인스턴스)의프로토타입을 할당하기 위해 사용 |
//생성자 함수
function Person(name) {
this.name = name;
}
const me = new Person('Lee');
//결국 Person.prototype과 me.__proto__는 동일한 프로토타입을 가리킨다.
console.log(Person.prototype === me.__proto__);
모든 프로토타입은
constructor
프로퍼티를 갖는다.
이 constructor프로퍼티는 프로퍼티로 자신을 참조하고 있는 생성자 함수를 가리킨다.
이 연결은 생성자 함수가 생성될 때, 즉 함수 객체가 생성될 때 이뤄진다.
function Person(name) {
this.name = name;
}
const me = new Person('Lee');
//me 객체의 생성자 함수는 Person
console.log(me.constructor === Person); //true
prototype
, constructor
프로퍼티에 의해 연결되어 있기 때문이다.리터럴 표기법 | 생성자 함수 | 프로토타입 |
---|---|---|
객체 리터럴 | Object | Object.prototype |
함수 리터럴 | Function | Function.prototype |
객체는 리터럴 표기법 또는 생성자 함수에 의해 생성되므로 결국 모든 객체는 생성자 함수와 연결되어 있다.
Object.prototype
이다.Object
, String
, Number
, Function
, Array
, RegExp
, Date
, Promise
등과 같은 빌트인 생성자 함수도 일반 함수와 마찬가지로 빌트인 생성자 함수가 생성되는 시점에 프로토타입이 생성된다.
[[Prototype]]
내부 슬롯에 할당된다.객체의 다양한 생성방식
1. 객체 리터럴
2. Object 생성자 함수
3. 생성자 함수
4. Object.create 메서드
5. 클래스(ES6)
OrdinaryObjectCrearte
는 빈 객체를 생성한 후,[[Prototype]]
내부 슬롯에 할당한 다음,OrdinaryObjectCreate
에 전달되는 인수에 의해 결정된다.const obj = {x:1};
위 객체리터럴이 평가되면 추상연산에 의해 Object 생성자 함수와 Object.prototype과 생성된 객체 사이에 연결이 만들어진다.
const obj = {x:1};
// obj.__proto__ = Object.prototype
console.log(obj.constructor === Object); //true
console.log(obj.hasOwnProperty('x')); //true
const obj = new Object();
obj.x = 1;
//Object 생성자 함수에 의해 생성된 obj 객체는 Object.prototype을 상속받는다.
// obj.__proto__ = Object.prototype
console.log(obj.constructor === Object); //true
console.log(obj.hasOwnProperty('x')); //true
function Person(name) {
this.name = name;
}
const me = new Person('Lee');
console.log(me.constructor === Person); //true
Object.prototype은 다양한 빌트인 메서드를 갖고 있지만, 사용자 정의 생성자 함수 Person과 더불어 생성된 프로토타입 Person.prototype의 프로퍼티는 constructor 뿐이다.
프로토타입에 프로퍼티를 추가/삭제 가능(확장 기능)
function Person(name) {
this.name = name;
}
// 프로토타입 메서드
Person.prototype.sayHello = function () {
console.log(`Hi! My name is ${this.name}`);
};
const me = new Person('Lee');
const you = new Person('Kim');
me.sayHello(); // Hi! My name is Lee
you.sayHello(); // Hi! My name is Kim
//hasOwnProperty는 Object.prototype의 메서드다.
console.log(me.hasOwnProperty('name'));//true