자바스크립트는 명령형, 함수형, 프로토타입 기반, 객체지향 프로그래밍을 지원하는 멀티 패러타임 프로그래밍 언어다.
객체지향 프로그래밍은 여러 독립적 단위, 객체의 집합으로 프로그램을 표현하는 프로그래밍 패러다임
다양한 속성 중에서 프로그맹에 필요한 속성만 간추려 표현한 것
ex)
// 이름과 주소 속성을 갖는 객체
const person = {
name: 'Lee',
address: 'Seoul'
};
console.log(person); // {name: "Lee", address: "Seoul"}
이름과 주소 속성으로 표현된 객체인 person
을 다른 객체와 구별하여 인식
자바스크립트는 프로토타입을 기반으로 상속을 구현하여 중복을 제거한다.
// 생성자 함수
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
Circle
생성자 함수가 생성한 인스턴스는 자신의 프로토타입, 즉 상위 부모 객체 역할을 하는 Circle.prototype
의 모든 프로퍼티와 메서드를 상속한다.
모든 객체는
[[Prototype]]
이라는 내부 슬롯을 가지며, 객체 생성 방식에 따라 프로토타입이 결정되고[[Prototype]]
에 저장된다.
모든 객체는 __proto__
접근자 프로퍼티를 통해 [[Prototype]]
내부 슬롯에 간접적으로 접근할 수 있다.
Prototype관련 블로깅
생성자 함수에 의해 생성된 인스턴스느 프로토타입의 constructor
프로퍼티에 의해 생성자 함수와 연결된다. 이때 constructor
프로퍼티가 가리키는 생성자 함수는 인스턴스를 생성한 생성자 함수이다.
// obj 객체를 생성한 생성자 함수는 Object다.
const obj = new Object();
console.log(obj.constructor === Object); // true
// add 함수 객체를 생성한 생성자 함수는 Function이다.
const add = new Function('a', 'b', 'return a + b');
console.log(add.constructor === Function); // true
// 생성자 함수
function Person(name) {
this.name = name;
}
// me 객체를 생성한 생성자 함수는 Person이다.
const me = new Person('Lee');
console.log(me.constructor === Person); // true
프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성된다.
생성자 함수로서 호출할 수 있는 함수 constructor
는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 생성된다.
// 함수 정의(constructor)가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.
console.log(Person.prototype); // {constructor: ƒ}
// 생성자 함수
function Person(name) {
this.name = name;
}
function Person(name) {
this.name = name;
}
// 프로토타입 메서드
Person.prototype.sayHello = function () {
console.log(`Hi! My name is ${this.name}`);
};
const me = new Person('Lee');
// hasOwnProperty는 Object.prototype의 메서드다.
console.log(me.hasOwnProperty('name')); // true
Person 생성자 함수에 의해 성성된 me
객체는 Object.prototype
의 메서드인 hasOwnProperty
를 호출할 수 있다.
-> me
객체가 Person.prototype
뿐 아니라 Object.prototype
도 상속받은걸 의미한다.
me
객체의 프로토타입은 Person.prototype
이다.
Object.getPrototypeOf(me) === Person.prototype; // -> true
Object.getPrototypeOf(Person.prototype) === Object.prototype; // -> true
const Person = (function () {
// 생성자 함수
function Person(name) {
this.name = name;
}
// 프로토타입 메서드
Person.prototype.sayHello = function () {
console.log(`Hi! My name is ${this.name}`);
};
// 생성자 함수를 반환
return Person;
}());
const me = new Person('Lee');
// 인스턴스 메서드
me.sayHello = function () {
console.log(`Hey! My name is ${this.name}`);
};
// 인스턴스 메서드가 호출된다. 프로토타입 메서드는 인스턴스 메서드에 의해 가려진다.
me.sayHello(); // Hey! My name is Lee
프로토타입이 소유한 프로퍼티를 프로토타입 프로퍼티, 인스턴스가 소유한 프로퍼티를 인스턴스 프로퍼티라고 부른다.
인스턴스 메서드 sayHello
는 프로토타입 메서드 sayHello
를 오버라이딩했고 프로토타입 메서드 sayHello
는 가려진다.
상속 관계에 의해 프로퍼티가 가려지는 현상을
프로퍼티 섀도잉
이라 한다.
상위 클래스가 가진 메서드를 하위 클래스가 재정의하여 사용
함수 이름은 동일하지만 매개변수의 타입, 개수가 다른 메서드를 구현하고 매개변수에 의해 메서드를 구별하여 호출하는 방식
이항 연산자로서 좌변에 객체를 가리키는 식별자 우변에 생성자 함수를 가리키는 식별자를 피연산자로
객체 instanceof 생성자 함수
우변의 생성자 함수의 prototype에 바인딩된 객체가 좌변의 객체의 프로토타입 쳉니 상에 존재하면 true
// 생성자 함수
function Person(name) {
this.name = name;
}
const me = new Person('Lee');
// Person.prototype이 me 객체의 프로토타입 체인 상에 존재하므로 true로 평가된다.
console.log(me instanceof Person); // true
// Object.prototype이 me 객체의 프로토타입 체인 상에 존재하므로 true로 평가된다.
console.log(me instanceof Object); // true
새로운 객체를 생성, 첫 번째 매개변수에 생성할 객체의 프로토타입으로 지정할 객체를 전달, 두번째 매개변수는 생성할 객체의 프로퍼티 키와 프로퍼티 디스크립터 객체로 이뤄진 객체 전달
// 프로토타입이 null인 객체를 생성한다. 생성된 객체는 프로토타입 체인의 종점에 위치한다.
// obj → null
let obj = Object.create(null);
console.log(Object.getPrototypeOf(obj) === null); // true
// Object.prototype을 상속받지 못한다.
console.log(obj.toString()); // TypeError: obj.toString is not a function
// obj → Object.prototype → null
// obj = {};와 동일하다.
obj = Object.create(Object.prototype);
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
// obj → Object.prototype → null
// obj = { x: 1 };와 동일하다.
obj = Object.create(Object.prototype, {
x: { value: 1, writable: true, enumerable: true, configurable: true }
});
// 위 코드는 다음과 동일하다.
// obj = Object.create(Object.prototype);
// obj.x = 1;
console.log(obj.x); // 1
console.log(Object.getPrototypeOf(obj) === Object.prototype); // true
const myProto = { x: 10 };
// 임의의 객체를 직접 상속받는다.
// obj → myProto → Object.prototype → null
obj = Object.create(myProto);
console.log(obj.x); // 10
console.log(Object.getPrototypeOf(obj) === myProto); // true
// 생성자 함수
function Person(name) {
this.name = name;
}
// obj → Person.prototype → Object.prototype → null
// obj = new Person('Lee')와 동일하다.
obj = Object.create(Person.prototype);
obj.name = 'Lee';
console.log(obj.name); // Lee
console.log(Object.getPrototypeOf(obj) === Person.prototype); // true
const obj = { a: 1 };
obj.hasOwnProperty('a'); // -> true
obj.propertyIsEnumerable('a'); // -> true