본문 바로가기

Language & Framework/JavaScript

자바스크립트 기초. Class 어렵다~!~!~!~!~!~!~!~!

1. Class?

1) 객체를 생성하기 위한 틀 역할.

2) 클래스를 이용해 상속 및 다양성이 일어날 수 있으며 이런 표현을 가진 언어를 객체지향언어라고 부른다.

3) 클래스는 Hoisting되지 않으며 한 번만 선언된다.

4) 코드의 재사용성, 정리(clean code)를 위해 사용된다.

5) Ecma Sript6에서 추가된 문법이다. (형태만 다를 뿐 이미 클래스 생성하는 방법은 존재했다.)

 

· 클래스 선언 방법

class Smartphone {
  constructor(model, os, manufacturer) {
    // 클래스의 인스턴스 객체 생성, 초기화 (1개만 생성 가능하다)
    this.model = model;
    this.os = os;
    this.manufacturer = manufacturer;
  }
  // fields (속성)
  question() {
    return console.log(`why are you using ${this.model}?`);
    // method
  }
}

const mysmartphone = new Smartphone("iphone", "ios", "apple");
console.log(mysmartphone.model); // iphone
console.log(mysmartphone.os); // ios
console.log(mysmartphone.manufacturer); // apple 
mysmartphone.question(); // why are you using iphone?

사실 진짜 '선언 방법'만 다룬다면 class Smartphone {} 찍고 const smartphone = mysmartphobe 찍고 console.log(mysmartphone) 찍으면 되는데.. 그런 바보 같은 클래스는 쓸 일이 없다.

위의 클래스가 가장 기본적인 - 생성자, 속성, 메서드가 모두 포함된 - 클래스의 형태이다.

이게 현실적으로 가장 기본적이고 단순한 형태다.. 살려줘..

 

 

· getter(접근자)와 setters(설정자)

class Profile {
  constructor(name, age, dream) {
    this.name = name;
    this.age = age;
    this.dream = dream;
  }

  whatname() {
    return console.log(`my name is ${this.name}`);
  }
  whatage() {
    return console.log(`I'm ${this.age} years old`);
  }
  whatdream() {
    return console.log(`My dream is to be a ${this.dream}`);
  }
  get age() {
    return this._age;
  }

  set age(value) {
    this._age = value;
    if (value < 0) {
      this._age = 0;
    } else {
      return value;
    }
}

const ddoddis = new Profile("ddoddi", -10, "developer"); // Profile {name: 'ddoddi', _age: 0, dream: 'developer'}
ddoddis.whatname(); // my name is ddoddi
ddoddis.whatage(); // I'm 0 years old
ddoddis.whatdream(); // My dream is to be a developer
console.log(ddoddis); // Profile {name: 'ddoddi', _age: 1, dream: 'developer'}

위에서 다른 부분들은 크게 중요하지 않고 get과 set만 주의깊게 보면 된다.

getter는 값을 읽을 때 사용하고 setter는 값을 할당할 때 사용한다.

만약 age를 호출한다면 getter age가 선언된 순간부터 this.age를 호출하는 것이 아니라 get age를 호출하며 값을 입력할 때도  this age가 아니라 set age를 통해서 설정한다.

따라서 위의 경우 age에 할당된 -10이라는 파라미터가 set age의 value로 할당되는데 set age에서는 만약 value가 0보다 작을 경우 this._age의 값을 0으로 할당하도록 설정되어 있다.

그리고 getter의 return this._age를 통해 this_age가 아닌 setter에서 설정된 this._age가 호출되어 값을 반환한다.

* _를 붙이는 이유 : 언어상에서 강제되지 않으나 개발자들간에 암묵적으로 protected field로 취급 받음.

 

그냥 보기만 해도 머리가 깨질 것 같이 복잡한데 굳이 getter와 setter를 사용하는 이유가 무엇이냐? 코드의 캡슐화를 위해서이다.

1. 나이가 nagative가 되는 등 규칙에 어긋나는 무작위 값의 테러를 막을 수 있다.(안정성)

2. 실제 메서드와 변수에 접근하지 않고 값을 출력하여 사용자가 내부 정보에 직접 접근할 수 없게 한다.(보안성)

위와 같이 특별한 목적이 있는 것이 아니라면 굳이 getter와 setter를 사용할 필요는 없다.

 

 

· Private fields

protected fields와 달리 Private fields는 언어적 차원에서 보호를 받는다.

자손 클래스 및 클래스 외부에서 Private fields에게 접근할 수 없으며 이를 호출하려면 getter를 사용해야 한다.

사용법은 굉장히 간단하다, 기존 field 앞에 #만 붙여주면 된다.

class privateroom {
  publicfield = 3;
  #privatefield = 4; // private field

  get privatefield2() {
    return this.#privatefield;
  }
}

const privateddoddi = new privateroom();
console.log(privateddoddi.publicfield); //3
console.log(privateddoddi.privatefield); //undefined
console.log(privateddoddi.privatefield2); //4

 

· Static properties and method (정적 프로퍼티와 메서드)

 

프로퍼티가 아닌 클래스 자체에 메소드를 설정하는 것을 static method(정적 메서드)라고 한다.

class Practice {
  static staticmethod() {
    console.log(this === Practice);
  }
}

Practice.staticmethod(); // true

프로퍼티를 직접 클래스에 할당한 것 같이 설정하는 것을 static propertie(정적 프로퍼티)라고 한다.

이 기능은 괴장히 최근에 추가되었기 때문에 아직까지 크롬 브라우저에서만 지원한다.

class Practice2 {
  static ddoddi = "top dog";
}

console.log(Practice2.ddoddi); // top dog

 

정적 메서드와 프로퍼티는 용도에 맞게 사용할 경우 메모리 사용을 줄일 수 있다는 이점이 있지만 override가 불가능하며 객체지향언어의 문법으로써 부적절하다는 단점이 있다.

사실 크게 중요한 부분은 아닌 것 같아서 이 부분은 깊게 알아보지 않았다.. 진도 나가기도 힘들어 : (

나중에 시간이 나면 따로 더 배우고 글을 작성하도록 하겠다.

 

 

·  Inheritance (상속)

클래스에 있는 내용을 다른 클래스에게 계승하는 것을 inheritance라고 말한다.

코드가 길어지기 때문에 복잡해보일 수 있으나 크게 어려운 부분은 없다.

그러나 이 하나에 새로운 개념이 4개나 들어가 있으므로 눈을 크게 뜨고 봐야한다.

class Animal {
  constructor(name, size, eating) {
    this.name = name;
    this.size = size;
    this.eating = eating;
  }

  touch() {
    console.log(`you are bitten by the ${this.name}`);
  }

  run() {
    console.log(`The ${this.name} runs at great speed`);
  }
}

class Predator extends Animal { // 부모 Animal을 계승하는 Preadator 생성
  hungry() {
    console.log(`the ${this.name} is preparing to hunt...`); // 새로운 메서드 생성
  }
  run() {
    super.run(); // 부모의 내용을 계승
    console.log(`A ${this.name} rushes towards its prey`); // 새로운 구문 추가
  }
}
class Herbivores extends Animal {
  constructor(name, size, eating, skill) {
    super(name, size, eating); // 부모의 생성자를 먼저 읽는다
    this.skill = skill;
  }

  touch() {
    console.log(`the ${this.name} was delighted`); // 원래 있었던 메서드를 override
  }
  hungry() {
    console.log(`the ${this.name} is going to graze..`);
  }
  run() {
    super.run();
    console.log(`The ${this.name} hid in cover`);
  }
}

const lion = new Predator("simba", "mideum", "meat");
const rabbit = new Herbivores("pinky", "small", "carrot", "jump");
console.log(lion); //Predator {name: 'simba', size: 'mideum', eating: 'meat'}
console.log(rabbit); //Herbivores {name: 'pinky', size: 'small', eating: 'carrot', skill: 'jump'}
lion.touch(); //you are bitten by the simba
rabbit.touch(); //the pinky was delighted
lion.hungry(); //the simba is preparing to hunt...
rabbit.hungry(); //the pinky is going to graze..
lion.run(); //The simba runs at great speed
            //A simba rushes towards its prey
rabbit.run(); //The pinky runs at great speed
              //The pinky hid in cover

 

엄청 길다. 여기서 알아야할 내용은 4가지가 있다.

1) 상속 방법 : class 자식 클래스 이름 extend 부모 클래스 이름. 간단하니 바로 넘어가자.

2) 자식 클래스에서는 부모 클래스의 메소드를 그대로 상속 받지만 위에서 배운 #private으로 보호받는 메소드는 상속받지 못한다.

3) 자식 클래스에서 부모 클래스에 없던 메소드를 추가할 수 있으며 같은 메소드를 사용하고 다른 명령을 사용할 시 override되어 자식 클래스에서 지정한 값을 반환한다.

4) 기존 값을 유지하며 새로운 것을 추가하고 싶을 경우 (생성자 추가 및 기존 메소드에 다른 내용 추가) super()를 사용해 부모의 값을 먼저 불러오도록 지정해줘야 한다.

=> 아주 간단하게 설명하자면 JAVAScript에서는 변수 -> 자식 클래스 -> 부모 클래스 순서대로 구문을 확인하는데, 기존 값에 추가적인 내용을 넣으려고 하면 부모 클래스가 먼저 읽혀지지 않은 상태에서 자식 클래스에서 값을 출력하려고 하기 때문에 에레거 발생한다. 따라서 super()를 사용해 부모 클래스의 값을 먼저 읽도록 지정해줘야 한다.

 

 

 

· instanceof (객체타입 확인)

이전에 배운 typeof와 비슷한 기능으로 객체의 타입을 확인할 수 있다.

모든 객체는 오브젝트에 속하기 때문에 ~ instance Object는 무조건 true이다.

console.log(lion instanceof Animal); // true
console.log(Animal instanceof Herbivores); // false
console.log(Animal instanceof Object); // true
console.log(rabbit instanceof Predator); // false

 

 

 

 

 

--

 

 

후.. 진 빠진다 🥲