클래스, 객체, 인스턴스
클래스는 객체를 만들어내기 위한 설계도 혹은 틀이며, 연관되어 있는 변수와 메서드의 집합이다.
클래스는 객체 정의를 위한 상태(멤버변수)와 메서드(함수)로 구성된다.
클래스와 객체, 인스턴스 간 연관을 짧게 설명하자면
객체
소프트웨어 세계에서 구현할 대상으로, 클래스에 선언된 형태 그대로 생성된 실체이다.
인스턴스
클래스(설계도)로부터 구현된 구체적인 실체를 의미하며
클래스로부터 객체를 생성했다면, 그것을 인스턴스라고 부른다.
예를 들어, Person 클래스라면 Person 클래스로 구현한 Tom은 인스턴스이다.
객체와 인스턴스의 관계는 다음과 같다.
1. 인스턴스는 객체에 포함된다.
2. oop 관점에서, 객체가 메모리에 할당되어 실제로 사용
되면 "인스턴스" 라고 한다.
3. 추상적
개념과 구체적
객체 사이 "관계"
에 초점을 맞춘다.
1. "~의 인스턴스"
라는 이름으로 불린다.
2. 객체는 클래스의 인스턴스
다.
3. 객체간 링크는, 클래스 간 연관관계의 인스턴스다.
4. 실행 프로세스는, 프로그램의 인스턴스
다.
→ 사실 이와 같이 인스턴스라는 용어는 반드시 클래스/객체 사이의 관계로 한정지어 사용할 필요는 없다.
4. 결론은, 인스턴스는 원본(추상적 개념)으로부터 생성된 복제본
이다.
클래스
클래스를 생성할 때는,
class Person{
constructor(name, age){
this.name = name;
this.age = age;
}
sayName(){
return `hi my name is ${this.name}`;
}
method2(){...}
method3(){...}
}
const tom = new Person('Tom', 23);
tom.sayName();
new 키워드와 함께 클래스 이름을 호출하고, 생성자(constructor)에서 받을 인자를 넣어준다.
생성자(constructor)는 객체의 기본 상태를 설정해주는데
new 키워드에 의해 자동 호출되어 클래스에 의해 생성될 객체를 초기화해준다.
위의 코드에서는,
1. Person 클래스(설계도)로부터 새로운 객체(구체적인 실체) tom을 생성한다.
2. 인수 'Tom', 23이 constructor에 의해 this.name, this.age에 할당된다.
클래스 분해하기
이전에는 자바스크립트에서는 클래스가 없어서 함수와 new 연산자를 활용해 클래스를 구현했었다.
그리고 ES2015(ES6)에서 추가되어서 클래스를 이용해 객체지향을 구현할 수 있다.
엄연히 말하면, 다른 언어의 클래스와는 차이가 있다.
자바스크립트에서 클래스는 Class 키워드를 사용하지만 내부적으로는 프로토타입을 따르기 때문이다.
다음 코드에서, Person 클래스의 인스턴스 tom을 보면
생성자와 sayName 메서드가 프로토타입에 구현이 되어 있다.
ES6에서 새롭게 등장한 개체가 아니기 때문이다.
사실, 자바스크립트에서 클래스는 함수의 일종이다.
실제로 위에서 구현한 클래스를 함수와 프로토타입, new 키워드로 구현할 수 있다.
function Person(name, age){
this.name = name;
this.age = age;
}
User.prototype.sayName = function(){
return `hi my name is ${this.name}`;
}
const tom = new Person('Tom', 23);
tom.sayName();
완전히 똑같은 객체는 아니지만, 거의 같다고 할 수 있는 객체와 내부 구현을 표현할 수 있다.
clsss 키워드가 하는 일은 다음과 같다.
1. 클래스 이름을 가진 함수를 만들고, 함수 본문(arg1,arg2,...)을 생성자에서 가져온다.
클래스에 생성자가 없을 수도 있어서 이 때는 본문()이 빈 함수가 만들어진다.
2. 해당 함수의 프로토타입에 클래스에서 정의한 메서드들을 저장한다.
클래스와 생성자 함수 방식의 차이
두 방식이 결국 프로토타입을 이용하며 new 키워드를 사용하는 점에서 유사하지만
클래스는 단순히 생성자 함수를 편하게 쓰기 위한 그 자체이지는 않다.
function 키워드로 생성한 Person 함수는, Person()의 호출과 new Person()의 호출이 가능해서
new 키워드로만(+정확히 말하면 파스칼케이스인 함수 이름까지) 생성자함수 사용을 고려하는 반면
class 키워드에 의해 생성된 함수에서는 특수 프로퍼티 IsClassConstructor가 있으며 true 값을 가진다.
이 프로퍼티에 의해 해당 함수는 new 키워드 없이 호출할 수 없다.
또한 console.log(Person); 와 같이 문자열화해서 클래스를 출력할 때
class의 내부 구현 형태가 나타나는데, 이것 또한 IsClassConstructor의 덕분이라고 한다.
두번째 차이로는, 클래스 메서드는 열거가 불가능하다.
이전에 프로퍼티 플래그에서 학습한 enumerable이 false인 것인데,
생성자 함수를 통해 만든 객체를 순회할 때는 메서드가 enumerable이 true라는 의미일테니 코드를 통해 살펴보자.
먼저 생성자 함수를 통해 객체를 만들면
프로토타입에 정의된 sayName 메서드가 조회된다.
그러나 클래스를 통해 생성된 객체에서는 조회되지 않는다.
for... in, Object.keys, Object.entries 등의 객체 프로퍼티를 조회하는 메서드는
Number, string, Array 등의 값을 가진 프로퍼티를 조회하는 목적이 크고
프로퍼티 메서드를 순회하려는 목적으로 사용해본 적은 없는 듯 하다.
그 외에 클래스는 use strict(엄격 모드)로 실행이 되며
extends, super 키워드를 통한 쉬운 상속 구현이 가능한 점 등등의 차이가 있다.
(물론 생성자 함수에서도 프로토타입을 이용하면서 상속을 구현할 수 있다.)
Getter & Setter
이전에 다룬 Getter, Setter 포스팅에서 클래스에서도 사용이 가능하다고 했다.
class Person{
constructor(name, age){
this.name=name;
this.age=age;
} // 생성자가 없으면 setter가 동작하지 않는다.
get name(){
return this._name;
}
set name(value){
if(value.length < 3){
console.log("이름은 3글자 이상이어야 합니다.");
return;
}
this._name=value;
}
}
const tom = new Person('Tom', 23);
console.log(tom.name); // Tom
tom.name = 'aa'; // 이름은 3글자 이상이어야 합니다.
console.log(tom.name); // Tom
다음과 같이 getter와 setter를 사용할 수 있다.
getter와 setter 역시 프로토타입에 정의되며, 특정 프로퍼티의 호출, 할당, 변경에 대해 부가적인 옵션을 부여할 수 있다.
'JavaScript > theory' 카테고리의 다른 글
자바스크립트의 this는 어떻게 결정되는가? (0) | 2022.01.25 |
---|---|
자바스크립트의 undefined, null에 대해 알아보자. (0) | 2022.01.19 |
객체 프로퍼티의 getter와 setter (0) | 2022.01.17 |
객체 프로퍼티 플래그와 설명자(Flag & Descriptor) (0) | 2022.01.17 |
래퍼 객체(Wrapper Object)란? (0) | 2022.01.14 |