데브코스 14일차 ( 24.10.31 목 ) JavaScript

워니·2024년 10월 31일
0

Programmers Front-end

목록 보기
14/27

[Section 02] JavaScript 심화


< 13. Class >

  • 프로토타입을 쉽게 사용하기 위한 Sugar Syntax (설탕 문법)
  • Sugar Syntax (설탕 문법) : 기존 문법을 쉽게 사용할 수 있게 해주는 것

1. class 문법 작성 방법

1.1. class 기본 형태

  • 생성자 함수를 쉽게 사용하기 위한 Sugar Syntax
  • class 키워드를 사용해서 선언
  • class 내부에 constructor 메소드를 가지고 있다
ex 1)
class Person {
  getInfo() {
    // getInfo는 프로토타입에 들어가 있음
    // 함수선언문에서 function만 빼기
    console.log("hello, Person Class");
  }
}
const person = new Person();
person.getInfo(); // hello, Person Class
console.dir(person);
ex 2)
class Person {
  constructor(name, age) {
    //초기 멤버 속성이 필요할 때 constructor 사용
    this.name = name;
    this.age = age;
  }
  getInfo() {
    console.log(`${this.name}, ${this.age}`);
  }
}
const person = new Person("길동", 20);
person.getInfo();

1.2. 문자열을 나타내는 class 문법

class Person {
  constructor() {
    console.log("Person Class");
  }
}
const personC = new Person();
// new라는 키워드로 인스턴스를 생성하려고 할 때 
// constructor는 최초 한 번 실행 됨

1.3. 문자열과 매개변수를 나타내는 class 문법

1) 생성자 함수
function PersonF(name, age) {
  this.name = name;
  this.age = age;
}
const personF = new PersonF("철수", 20);
console.dir(personF);

2) 생성자함수로 작성한 것을 좀 더 쉽게 작성할 수 있도록 하는 문법 작성 방법
// 아래처럼 작성하면 위처럼 작성한 것처럼 취급해주는 것이다.

class Person {
  // Person이라는 class는 객체도 아니고 함수도 아니다
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}
const personC = new Person("영희", 30);
console.dir(personC);

1.4. getInfo 매서드, 매개변수 추가

1) 생성자 함수
function PersonF(name, age) {
  this.name = name;
  this.age = age;
  this.getInfo = function () {
    console.log(`${this.name}, ${this.age}`);
  };
}
const personF = new PersonF("철수", 20);
personF.getInfo();
console.dir(personF);
// getInfo가 멤버 속성에 있음
// 빼려면 프로토타입으로 빼줘야 함

2) class 문법

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  getInfo() {
    // 애초부터 멤버 속성에 들어가 있지 않음(프로토타입에 있음)
    console.log(`${this.name}, ${this.age}`);
  }
}
const personC = new Person("영희", 30);
personC.getInfo();
console.dir(personC); // 애당초에 getInfo가 프로토타입에 들어가 있음

2. class 상속 방법

  • extends 키워드를 사용해서 상속한다.
  • extends로 속성을 불러오려면 constructor안에 super()를 꼭 함께 사용해야 한다.
  • 상속 여부와 관계 없이 constructor를 가지고 있어야 한다.
  • 예시 1
    1) 생성자 함수 상속
    function Car(name) {
      this.name = name;
    }
    Car.prototype.getInfo = function () {
      console.log(`${this.name}`);
    };
    const car = new Car("benz");
    car.getInfo();
    
    function Benz(name, color) {
      Car.call(this, name);
      this.color = color;
    }
    Benz.prototype = Object.create(Car.prototype);
    Benz.prototype.constructor = Benz;
    Benz.prototype.getColor = function () {
      console.log(`${this.color}`);
    };
    const benz = new Benz("e-class", "black");
    benz.getInfo();
    benz.getColor();
    
    2) class 상속
    class Car {
      constructor(name) {
        this.name = name;
      }
      getInfo() {
        console.log(`${this.name}`);
      }
    }
    const car = new Car("benz");
    car.getInfo();
    
    class Benz extends Car {
      // Car에 있는 모든 속성에 Benz가 접근 가능
      constructor(name, color) {
        super(name);
        this.color = color;
      }
      getColor() {
        console.log(`${this.color}`);
      }
    }
    const benz = new Benz("e-class", "black");
    benz.getInfo();
    benz.getColor();
  • 예시2
    class Person {
      constructor(name, age) {
        this.name = name;
        this.age = age;
      }
      greet() {
        console.log(`hello. ${this.name},${this.age}`);
      }
    }
    class Employee extends Person {
      constructor(name, age, position) {
        super(name, age); // extends로 속성을 불러올 거면 super를 사용해야 함
        this.position = position;
      }
      getJob() {
        console.log(`my job is ${this.position}`);
      }
    }
    const developer = new Employee("길동", 20, "개발자");
    developer.getJob();
    console.dir(developer);

3. 정적 매서드 사용 방법 (static)

  • 인스턴스를 생성하지 않고 사용할 수 있는 매서드 static

3.1. 정적 매서드 정의 방법

// ex 1)
class Person {
  static GENDER = "male";
  static getInfo() {
    return "나는 남자";
  }
}
console.log(Person.GENDER); // 속성은 속성명만
console.log(Person.getInfo()); // 매서드는 매서드명()
1) class 문법
class MathUtils {
  // 멤버 속성이 필요한 경우에만 constructor 사용
  add(n1, n2) {
    return n1 + n2;
  }
}
const math = new MathUtils();
const sum = math.add(10, 20);
console.log(sum);
// add 매서드는 MathUtils의 멤버 속성에 의해서 결정되는 것이 아니다
// 인스턴스를 만든다는 것 자체가 메모리를 소비하는 것인데 굳이??

2) 인스턴스 생성 없이 정적 매서드 사용
class MathUtils {
  static add(n1, n2) {
    // static 키워드 붙이면 인스턴스 생성을 통해 접근이 안 됨
    return n1 + n2;
  }
}
// const math = new MathUtils(); 필요 없어짐
// const sum = math.add(10, 20); 필요 없어짐
const sum = MathUtils.add(10, 20);
// class명으로 직접 접근 해야 된다
console.log(sum);

3) 생성자 함수로 바꾸면
function Mathss() {}
Mathss.add = function (a, b) {
  return a + b;
};
console.log(Mathss.add(10, 20));

3.2. 정적 속성 접근 방법

  • 정적 속성은 대문자로 이름을 짓는 관례가 있음
1) 정적 매서드 사용 class
class MathUtils {
  static PI = 3.14;
}
console.log(MathUtils.PI);

2) 생성자 함수로 변환
function Mathss() {}
Mathss.PI = 3.14;
console.log(Mathss.PI);

4. 접근 제어자: get, set

  • 인스턴스 객체의 속성 값을 바꿀 때, 바꾸는 것을 제어하고 싶은 경우 사용
1) 논리적으로 맞지 않는 경우
class Car {
  constructor(speed) {
    this.speed = speed;
  }
}
const car = new Car(200);
car.speed = -100;
// 스피드가 마이너스 값이 없으므로 논리적으로 맞지 않게 됨
console.log(car.speed); // -100

2) 제어하고 싶다면?
class Car {
  constructor(speed) {
    this._speed = speed;
    // 초기값 이름을 다르게 해줘야 무한 루프 안 걸림
  }
  set speed(value) {
    this._speed = value < 0 ? 0 : value;
  }
  // 제어하고 싶은 값을 함수로 지정, 여기서는 speed
  // set 키워드를 사용할 때는 매개변수를 하나 무조건 넣어야 함
}
const car = new Car(200);
car.speed = -100;
console.log(car._speed); // 200

3) 외부 셋팅은 그대로 유지하고 싶다면?
class Car {
  constructor(speed) {
    this._speed = speed;
    // 초기값 이름을 다르게 해줘야 무한 루프 안 걸림
  }
  set speed(value) {
    this._speed = value < 0 ? 0 : value;
  }
  get speed() {
    return this._speed;
    // set, get은 멤버 속성에 대한 접근을 제어하고 싶을 때 사용
    // 외부 셋팅은 유지시켜주는 것이 get
  }
}
const car = new Car(200);
car.speed = -100;
console.log(car.speed);
  • 예시
    class Car {
      constructor(color, speed) {
        this._color = color;
        this._speed = speed;
      }
      set color(value) {
        this._color = value === "white" ? "white is not setting" : value;
      }
      set speed(value) {
        this._speed = value < 0 ? 0 : value;
      }
      get color() {
        return this._color;
      }
      get speed() {
        return this._speed;
      }
    }
    const car = new Car("blue", 200);
    car.color = "white";
    car.speed = -100;
    console.log(car.color);
    console.log(car.speed);

5. 프라이빗 필드: #

  • #으로 지정한 필드는 외부에서 접근 불가능
1) 조작 불가
class Car {
  #speed = 0; // #을 앞에 붙이면 외부에서 조작 불가
  constructor(color, speed) {
    this.#speed = speed;
  }
  set speed(value) {
    this.#speed = value < 0 ? 0 : value;
  }
  get speed() {
    return this.#speed;
  }
}
const car = new Car("blue", 200);
car.#speed = -100;
// Private field '#speed' must be declared in an enclosing class
console.log(car.speed);
  • 예시
    1) 조작 가능
    class Counter {
      constructor(count) {
        this.count = count;
      }
      increment() {
        this.count++;
      }
        this.count--;
      }
    }
    const count = new Counter(0);
    count.count = 200; // 조작 가능
    count.increment();
    count.increment();
    console.log(count.count); // 202
    
    2) 조작 불가
    class Counter {
      #count = 0;
      constructor(count) {
        this.#count = count;
      }
      increment() {
        this.#count++;
      }
      decrement() {
        this.#count--;
      }
      getCount() {
        return this.#count;
      } // 내부에 직접 저장을 해야 가능
    }
    const count = new Counter(0);
    count.count = 200;
    count.increment();
    count.increment();
    console.log(count.getCount()); // 2

6. 오버라이딩

  • 부모가 가지고 있는 매서드를 자식이 가진 것으로 씌우는 것
  • 매서드를 재정의하는 현상
  • 속성 앞에 언더바 (_)를 붙여주는 관례가 있음
class Animal {
  sound() {
    console.log("sound");
  }
}
class Dog extends Animal {
  run() {
    console.log("run");
  }
}
const dog = new Dog();
dog.run(); // run
dog.sound(); // sound, Animal에서 물려받음

/* 자식 class에 동일한 매서드를 작성하면 덮어씀 */
class Animal {
  sound() {
    console.log("sound");
  }
}
class Dog extends Animal {
  run() {
    console.log("run");
  }
  sound() {
    console.log("dog sound");
  }
}
const dog = new Dog();
dog.run(); // run
dog.sound(); // dog sound

7. 일급 객체

7.1. 객체의 조건

7.1.1 .변수에 할당이 가능해야 한다.

7.1.2. 함수의 인자로 전달할 수 있어야 한다.

7.1.3.. 함수의 반환 값으로 사용할 수 있어야 한다.

7.1.4. 동적으로 생성이 가능해야 한다.

7.2. 생성자 함수 일급객체 확인

// 1.1 변수에 할당이 가능해야 한다.
const sum = function () {}; // 함수 표현식

// 1.2 함수의 인자로 전달할 수 있어야 한다.
function greet(callback) {
  callback();
}
greet(() => {
  console.log("hello");
}); // 함수의 인자로 전달 가능

// 1.3 함수의 반환 값으로 사용할 수 있어야 한다.
function outer() {
  return function () {
    console.log("inner");
  };
}
const a = outer();
a(); // a함수의 반환 값으로 사용됨

// 1.4 동적으로 생성이 가능해야 한다.
const dynamicFunc = new Function("name", "return '안녕? ' + name");
// new Function(argument, return 값)
console.log(dynamicFunc("길동"));

함수는 객체가 아니지만 4가지 조건을 충족하므로 일급객체로 취급

7.3. class 일급객체 확인

// 1.1 변수에 할당이 가능해야 한다.
class Person {
  constructor(name) {
    this.name = name;
  }
}
const MyClass = Person;
const person = new MyClass("철수");
console.dir(person);

// 1.2 함수의 인자로 전달할 수 있어야 한다.
class Person {
  constructor(name) {
    this.name = name;
  }
}
function createInstance(ClassName, args) {
  return new ClassName(args);
}
const person = createInstance(Person, "길동");
console.dir(person);

// 1.3 함수의 반환 값으로 사용할 수 있어야 한다.
function makePersonClass() {
  return class {
    constructor(name) {
      this.name = name;
    }
  };
}
const MakePerson = makePersonClass();
const p = new MakePerson("길동");
console.dir(p);

// 1.4 동적으로 생성이 가능해야 한다. (이거 다시 확인 필요)
const className = "DynamicClass";
const DynamicClass = new Function(
  "return class { constructor(name){this.name = name;} greet() {console.log('hello')} }"
)();

const instance = new DynamicClass("철수");
instance.greet();

< 하루 정리 >

오늘 배운 내용은 최근 며칠동안에 비해선 머리에 잘 들어왔다.
물론 수업이 끝난 후 밥을 먹고 연습문제를 다시 풀어보면 막히겠지만,
그래도 머리를 쥐어짜면서 괴로워하던 시간들을 없었으니 다행이다.

이제 어느 정도 배우기도 했고 이걸 잘 사용할 수 있어야 하는데,
아직은 그 정도의 실력이 안 된다. 뒤돌아서면 다 잊어버린다...
오늘 수업시간에 역량평가 얘기가 나왔는데 생각만 해도 아찔하다...
1차 테스트가 너무 쉬워서 다들 잘 풀거라고 강사님께서 말씀하셨지만,
그 다들에는 내가 포함되어 있지 않는다는 걸 잘 안다....

주말 시간도 잘 활용해서 계속 문제 풀어보고 익숙해져야겠다.

앉아서 컴퓨터로 공부만 하는 건데도 체력 소모가 엄청 많은가보다.
살이 빠지고 아침에 일어나기가 점점 더 힘들어진다.
먹는 양은 늘어나는데 그 이상으로 에너지를 쏟아붓고 있나보다 ㅠㅠ

더 지치지 않게 체력 관리 잘 하자!!
profile
첫 시작!

0개의 댓글