즉, 이렇게 클래스는 객체를 만들기 위한 설계도라고 생각할 수 있고, 이 설계도를 바탕으로 만들어진 실제 객체들은 인스턴스라고 할 수 있다.😯
class Person {
// constructor는 이름을 변경할 수 없어요 !!
constructor(name, age) {
// 이름(name)과 나이(age)가 없으면 사람이 아니죠?
// new라는 키워드를 이용해서 인스턴스를 만들 때, 기본적으로 넣어야 하는 값들을 의미
// 여기서 말하는 this는 만들어질 인스턴스를 의미
this.name = name;
this.age = age;
}
// 다양한 메소드를 아래와 같이 정의할 수 있어요.
// 여기서 this.name으로 내부 값을 접근해야 함!!!
sayHello() {
console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
}
}
const person1 = new Person("Alice", 30);
const person2 = new Person("Bob", 25);
// 만든 객체를 토대로 메서드 호출해보기
person1.sayHello(); // 출력: "Hello, my name is Alice and I am 30 years old."
person2.sayHello(); // 출력: "Hello, my name is Bob and I am 25 years old."
위 코드에서 Person Class는 name과 age 속성을 가지고 있으며, sayHello 메소드를 정의한다. 그리고 new 키워드를 사용하여 Person Class의 인스턴스를 생성하고, sayHello 메소드를 호출
class Person {
constructor(name, age) { // constructor
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
}
}
const person = new Person('Alice', 20);
class supercar {
constructor(modelName, modelYear, type, price) {
this.modelName = modelName;
this.modelYear = modelYear;
this.type = type;
this.price = price;
}
// 클락션 울리는 메서드
makenoise() {
console.log(
this.modelName + "는" + this.modelYear + "년도 자동차 이무니다."
);
}
}
// 슈퍼카 만들기
let supercar1 = new supercar("람보르기니", "2023", "e", 5000);
let supercar2 = new supercar("우루스", "1992", "G", 5000);
let supercar3 = new supercar("제네시스", "2017", "D", 5000);
supercar1.makenoise();
supercar2.makenoise();
supercar3.makenoise();

잘 출력이 되었따 !
Class에서는 getter와 setter를 사용하여 Class의 속성에 접근할 수 있다! getter는 속성 값을 반환하는 메소드이며, setter는 속성 값을 설정하는 메소드, 이를 통해 생성한 인스턴스를 정해진 규격 안에서 자유자제로 변경 가능!
Getter와 Setter 예시)
// Getters와 Setters
// 객체지향 프로그래밍 언어 -> G, S
// 클래스 --> 객체(인스턴스)
// 프로퍼티(constructor)
// new Class(a, b, c)
class Rectangle {
constructor(height, width) {
this._height = height; // this.뒤 height앞에 언더바 필수 !
this._width = width; // this.뒤 width앞에 언더바 필수 !
}
get width() { // width를 위한 getter
return this._width; // this.뒤 width앞에 언더바 필수 !
}
set width(value) { // width를 위한 setter
// 검증 1 : value가 음수이면 오류!
if (value <= 0) {
//
console.log("[오류] 가로길이는 0보다 커야 합니다!");
return;
} else if (typeof value !== "number") {
console.log("[오류] 가로길이로 입력된 값이 숫자타입이 아닙니다!");
return;
}
this._width = value; // this.뒤 width앞에 언더바 필수 !
}
get height() { // height를 위한 getter
return this._height; // this.뒤 height앞에 언더바 필수 !
}
set height(value) { // height를 위한 setter
// 검증 1 : value가 음수이면 오류!
if (value <= 0) {
//
console.log("[오류] 세로길이는 0보다 커야 합니다!");
return;
} else if (typeof value !== "number") { // 그냥 number 라고 입력하면 변수로 인식함
console.log("[오류] 세로길이로 입력된 값이 숫자타입이 아닙니다!");
return;
}
this._height = value;
}
getArea() { // getArea : 가로 * 세로 => 넓이
const a = this._width * this._height;
console.log(`넓이는 => ${a}입니다.`);
}
}
// instance 생성
const rect1 = new Rectangle(10, 7);
rect1.getArea();
// const rect2 = new Rectangle(10, 30);
// const rect3 = new Rectangle(15, 20);
// 클래스 연습해보기!
// [요구사항]
// 1. Car라는 새로운 클래스를 만들되, 처음 객체를 만들 때는
// 다음 네 개의 값이 필수로 입력돼야 합니다!
// (1) modelName
// (2) modelYear
// (3) type : 가솔린, 전기차, 디젤
// (4) price
// 2. makeNoise() 메서드를 만들어 클락션을 출력해주세요.
// 2-1. 해당 자동차가 몇년도 모델인지 출력하는 메서드 작성!
// 3. 이후 자동차를 3개 정도 만들어주세요(객체 생성)
// [추가 요구사항]
// 1. modelName, modelYear, price, type을 가져오는 메서드
// 2. modelName, modelYear, price, type을 세팅하는 메서드
// 3. 만든 인스턴스를 통해서 마지막에 set 해서 get 하는 로직까지
class Car {
constructor(modelName, modelYear, type, price) {
this._modelName = modelName; // set get 시 this. 뒤에 언더바_ 꼭 !
this._modelYear = modelYear;
this._type = type;
this._price = price;
}
get modelName() {
return this._modelName;
}
// 입력값에 대한 검증까지 가능하다
set modelName(value) {
if (value.length <= 0) { // 모델명 유효성 검사
console.log("[오류] 모델명이 입력되지 않았습니다. 확인해주세요!");
return;
} else if (typeof value !== "string") {
console.log("[오류] 입력된 모델명이 문자형이 아닙니다!");
return;
}
this._modelName = value; // 검증이 완료된 경우에만 setting!
}
get modelYear() {
return this._modelYear;
}
set modelYear(value) {
if (value.length !== 4) { // 년도 유효성 검사
// 연도에 대한 유효성 검증 로직 ---> googling 엄청~~~~많이 나옵니다!!
console.log("[오류] 입력된 년도가 4자리가 아닙니다.확인해주세요!");
return;
} else if (typeof value !== "string") {
console.log("[오류] 입력된 모델명이 문자형이 아닙니다!");
return;
}
this._modelYear = value; // 검증이 완료된 경우에만 setting!
}
get type() {
return this._type;
}
set type(value) {
if (value.length <= 0) {
console.log("[오류] 타입이 입력되지 않았습니다. 확인해주세요!");
return;
} else if (value !== "g" && value !== "d" && value !== "e") {
// g(가솔린), d(디젤), e(전기차)가 아닌 경우 오류
console.log("[오류] 입력된 타입이 잘못되었습니다. 확인해주세요!");
return;
}
// 검증 완료!
this._type = value;
}
get price() {
return this._price;
}
set price(value) {
if (typeof value !== "number") {
console.log("[오류] 가격으로 입력된 값이 숫자가 아닙니다. 확인해주세요!");
return;
} else if (value < "1000000") {
console.log("[오류] 가격은 100만원보다 작을 수 없습니다. 확인해주세요!");
return;
}
// 검증이 완료된 경우
this._price = value;
}
// 클락션을 울리는 메서드
makeNoise() {
console.log(this._modelName + ": 빵!");
}
// 해당 자동차가 몇년도 모델인지 출력하는 메서드 작성!
printModelYear() {
console.log(
this._modelName + "은 " + this._modelYear + "년도의 모델입니다."
);
}
}
// 자동차 만들기
const car1 = new Car("Sorento", "2023", "e", 5000);
const car2 = new Car("SM5", "1999", "g", 3000);
const car3 = new Car("Palisade", "2010", "d", 4500);
// car1.makeNoise();
// car1.printModelYear();
// car2.makeNoise();
// car2.printModelYear();
// car3.makeNoise();
// car3.printModelYear();
// getter 예시1
console.log(car1.modelName);
// setter 예시1
car1.modelName = 1;
console.log(car1.modelName);
subclass 또는 derived class라고 하며, 상속을 하는 Class를 superclass 또는 base class라고 한다.class Animal { // 동물 전체에 대한 클래스
constructor(name) { // 이름 필수로 받기
this.name = name;
}
speak() { // 메서드 짖다 !
console.log(`${this.name} makes a fuckin noise.`);
}
}
class Dog extends Animal {
// extends를 통해 동물 클래스를 상속받는 Dog클래스를 만들기
// 이러한 부모에게서 내려받은 메서드를 재정의 하는것을 overriding 이라고 한다 !
// overriding !!!
speak() { // 상속받을 때, speak()를 입맛에 맞게 재정의
console.log(`${this.name} barks.`);
}
}
// Dog를 만들 때는 Animal의 상속을 받은 class이기 때문에 이름을 필수로 받아야 함 !!
let d = new Dog('Mitzie');
// speak는 'makes a fuckin noise'가 아니라, 'barks'가 출력되네요.
d.speak(); // "Mitzie barks."
class Calculator {
static add(a, b) {
return a + b;
}
static subtract(a, b) {
return a - b;
}
}
console.log(Calculator.add(1, 2)); // 3
console.log(Calculator.subtract(3, 2)); // 1

클로저란 함수와 그 함수가 선언된 렉시컬 환경과의 조합을 의미한다.. 뭔가 어려워 보이지만 JS의 강력한 기능이라니 한번 클로저에 대해 알아보도록 하자
예시 1) 함수가 선언된 렉시컬 환경
const x = 1;
function outerFunc() {
const x = 10;
function innerFunc() {
console.log(x); // x는 스코프 내부에서 x값을 찾지만 없음
} // 없는 경우 scope chain에 의해 바로 바깥쪽 scope를 찾는다. 그래서 10에 먼저 접근 // 10
innerFunc();
}
outerFunc();
예시 2) 만약 아래와 같다면, innerFunc()에서 출력하는 x값은 어떻게 될까?
const x = 1;
// innerFunc()에서는 outerFunc()의 x에 접근할 수 없죠.
// Lexical Scope를 따르는 프로그래밍 언어이기 때문
function outerFunc() {
const x = 10;
innerFunc(); // 1
}
function innerFunc() {
console.log(x); // 1
}
outerFunc();
const x = 1;
function foo() {
const x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
const x = 1;
function foo() {
const x = 10;
// 상위 스코프는 함수 정의 환경(위치)에 따라 결정된다.
// 함수 호출 위치와 상위 스코프는 아무런 관계가 없다.
bar();
}
// 함수 bar는 자신의 상위 스코프, 즉 전역 렉시컬 환경을 저장하여 기억한다.
function bar() {
console.log(x);
}
foo();
bar();
const x = 1;
// 1
function outer() {
const x = 10;
const inner = function () {
console.log(x);
};
return inner;
}
// outer함수를 '실행'해서 , innerFunc 담는다.
// outer함수의 return부분을 innerFunc 담는다는 뜻 !
const innerFunc = outer();
// --------------- 여기서 outer함수의 실행컨텍스는 날아간다.
innerFunc();
// 카운트 상태 변경 함수 #1
// 함수가 호출될 때마다 호출된 횟수를 누적하여 출력하는 카운터를 구현한다.
// 카운트 상태 변수
let num = 0;
const increase = function () { // 카운트 상태 변경 함수
return ++num; // 카운트 상태를 1만큼 증가시킨다.
};
console.log(increase()); // 1
console.log(increase()); // 1
console.log(increase()); // 1
이러한 의도치 않은 변경은 방지하면서 이전 상태를 유지하기 위해 우리는 Closure함수를 써야한다 !!// 카운트 상태 변경 함수 #3
const increase = (function () {
// 카운트 상태 변수
let num = 0;
// 클로저
return function () {
return ++num;
}; // increse 그 자체
})();
// 이전 상태값을 유지
console.log(increase()); //1
console.log(increase()); //2
console.log(increase()); //3
- 위 코드가 실행되면, '즉시 실행 함수'가 호출됨 !! => 함수가 반환(inner) => increse 에 할당
- increse 변수에 할당된 함수는 자신이 정의된 위치에 의해서 결정된 상위 스코프인 즉시 실행 함수의 '렉시컬 환경'을 기억한다.
- 쉽게말하면 클로저 -> let num = 0;을 기억한다
- 즉시 실행함수는 즉시 소멸됨 !