클래스와 인스턴스
new 키워드와 생성자 함수
class Meal{
//생략
}
let pizza = new Meal('pizza');
클래스를 이용해서 새로운 인스턴스를 만들고자 할 때는 반드시 new
키워드를 사용해야 한다.
만약에 생략했을 경우에는
TypeError: Class constructor Meal cannot be invoked without 'new'
이런식으로 정확히 명시해주기는 하지만 웬만하면 new
키워드를 적어주자.
//ES5
function IronMan(color,name) {
//인스턴스 만들어지고 난 후 실행될 코드
}
//ES6
class IronMan {
constructor(color,name) {
//인스턴스 만들어지고 난 후 실행될 코드
}
}
//ES5
function IronMan(color,name) {
this.color = color;
this.name = name;
}
//ES6
class IronMan {
constructor(color,name) {
this.color = color;
this.name = name;
}
}
//ES5
function IronMan(color,name) {
this.color = color;
this.name = name;
}
IronMan.prototype.fly = function(){
//prototype 키워드를 꼭 써줘야 함
}
//ES6
class IronMan {
constructor(color,name) {
this.color = color;
this.name = name;
}
fly() {
}
}
확실히 ES5보다 편한 거 같다… ES6 최고…
위 코드에서의 this는 그냥 클래스를 통해 만들어진 인스턴스 객체다. 그렇다고 아무데나 this를 남발했다간 큰일날 수(?) 있고 솔직히 this를 공부하다 보면 한도 끝도 없긴 하지만… 한번 this를 간단하게나마 알아보자.
functionlogThis() {
console.log(this);
}
logThis();// Window 객체
다만, use strict
키워드를 붙이게 되면 undefined
다.
var john = {
name: 'John',
greet: function() {
console.log('Hi! My name is ' + this.name);
}
};
john.greet();
일반 함수 내에서 this를 사용하게 되면 this.name
이 John
을 참조하고 있으므로
당연히 결과는 Hi! My name is John이 나온다.
이거를 arrow function으로 쓰면 어떻게 될까?
var john = {
name: 'John',
greet: () => console.log('Hi! My name is ' + this.name),
};
john.greet();
? this.name
이 어디로 갔을까?
콘솔에는 window
객체가 나오고 vscode 같은 곳들에서는 undefined
가 나오는데
두 경우 모두 arrow function 내에서는 this 참조를 못하고 바로 상위의 스코프를 참조하고 있기 때문에 저런 현상이 나오는 것이다.
설계도인 클래스, 이를 바탕으로 만들어진 인스턴스 객체를 Object로 해서 이러한 프로그래밍의 모든 것들을 하나의 객체로 간주하고 객체 간의 상호작용을 중심으로 생각하고 설계하는 프로그래밍 패러다임을 말한다.
캡슐화
내부 구조와 외부 구조를 독립적으로 생각하는 것을 말한다. 예를 들어 커피머신을 예로 들면 사용자는 단순히 버튼이나 다른 조작을 하지만 실제로 외부 구조에서는 복잡하게 돌아간다. 그리고 사용자가 그러한 구조를 몰라도 커피머신을 사용할 수 있기 때문에 서로 독립적이라고 볼 수 있다.
상속
class Animal {
constructor(name) {
this.speed = 0;
this.name = name;
}
run(speed) {
this.speed = speed;
alert(`${this.name} 은/는 속도 ${this.speed}로 달립니다.`);
}
stop() {
this.speed = 0;
alert(`${this.name} 이/가 멈췄습니다.`);
}
}
let animal = new Animal("동물");
객체를 여러개 만들어야 할 상황이 생길 수 있다. 그러나 위 코드처럼 클래스를 여러 개 사용하게 되면, 상당히 번거롭고 중간에 오타를 낼 확률도 적지 않다.
따라서, 상속이라는 개념을 이용하여 클래스를 상속받으면 된다.(실제로는 확장 개념에 더 가깝다고 한다.)
class Rabbit extends Animal {
hide() {
alert(`${this.name} 이/가 숨었습니다!`);
}
}
let rabbit = new Rabbit("흰 토끼");
rabbit.run(5); // 흰 토끼 은/는 속도 5로 달립니다.
rabbit.hide(); // 흰 토끼 이/가 숨었습니다!
다형성
여러 개의 객체가 각각 같은 메소드로 호출이 되더라도 클래스가 무엇이냐에 따라 실제 동작은 다른 성질을 다형성이라고 한다.
[[Prototype]]
이라는 숨김 프로퍼티라는 것을 갖는데 이 값은 null이거나 다른 객체에 대한 참조를 갖는다. 다른 객체를 참조하는 경우 이를 프로토타입이라 한다. 모든 객체는 __proto__
키워드를 이용해 접근이 가능하다.
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal;
alert( rabbit.eats );
alert( rabbit.jumps );
.__proto__
키워드를 이용하면 animal이 rabbit의 프로토타입이 된다.
function Person(first, last, age, gender, interests) {
// 속성과 메소드 정의
this.first = first;
this.last = last;
//...
}
console.log(Person.prototype)
함수 객체 내 프로퍼티를 확인해 본 결과
prototype이 존재한다.
// 함수 객체는 prototype 프로퍼티가 있음
function func() {}
func.hasOwnProperty('prototype') // true
// 일반 객체는 prototype 프로퍼티가 없음
const obj = {}
obj.hasOwnProperty('prototype') // false
// 화살표 함수
const arrowFunc = () => {}
arrowFunc.hasOwnProperty('prototype') // false
// ES6 축약 메서드
const es6 = {
test() {},
}
es6.test.hasOwnProperty('prototype') // true
화살표함수와 ES6 메소드에는 prototype 속성이 없다.
class Human {
constructor(name, age) {
this.name = name;
this.age = age;
}
sleep() {
console.log(`${this.name}은 잠에 들었습니다`);
}
}
let kimcoding = new Human('김코딩', 30);
// 실습해보세요
console.log(Human.prototype.constructor === Human)
Human.prototype === kimcoding.__proto__;
Human.prototype.sleep === kimcoding.sleep;
배열도 Array 생성자 함수로 만들어진 인스턴스이다.
[참고자료 - 모던 자바스크립트 Deep Dive]
자바스크립트 객체의 프로퍼티에 접근하려고 할 때, 프로퍼티가 존재하지 않을 경우 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색하는데 이를 프로토타입 체인이라 한다.
프로토타입의 체인의 최상위에 위치하는 객체는 언제나 Object.prototype
이다. 그렇기 때문에 모든 객체는 언제나 Object.prototype
을 상속받는다.
참고 자료
Javascript: Uncovering mysteries of 'this' keyword
[자바스크립트 js] 객체 지향 프로그래밍 4가지 개념 / 추상화 / 캡슐화 / 상속 / 다형성 / super / instanceof