1. Stack

 

  스택은 자료 구조의 일종으로, 마지막에 삽입된 항목만을 제거하고 접근할 수 있다.

  이러한 원리를 후입 선출(Last In First Out)이라고 부른다.

 

  스택은 속도가 빠르다는 점이 장점이다. 마지막 항목이 제거될 것을 알기 때문에 찾기와 삽입이 상수 시간인 O(1)이다.

  스택의 주요 메서드는 두 가지가 있다. 바로 Push와 Pop이다.

 

  1 - 1) push

    

    스택의 가장 마지막 인덱스에 데이터를 추가해준다.

 

  1 - 2) pop

 

    스택의 가장 마지막 인덱스의 데이터를 삭제한다.

 

  스택의 push와 pop 메서드 모두 마지막 인덱스에서 일어나므로 시간 복잡도는 O(1)이 된다.

  반면 특정 인덱스, 즉 예를 들어 n번째 데이터에 접근하기 위해서는 pop 메서드를 n번 호출해야 하므로 시간 복잡도는 O(n)이 된다.

 

 

 

2. Queue 

 

  큐는 스택과 달리 첫 번째 항목만을 제거할 수 있는 자료 구조다.

  이러한 원리를 선입선출(First In First Out)이라고 한다. 연산이 상수 시간이라는 점이 스택과 마찬가지로 장점이다.

  

  큐의 주요 메서드도 두 가지가 있다. 바로 Dequeue와 Enqueue이다.

 

  2 - 1) dequeue

    

    스택의 첫 번째 데이터를 삭제한다.

 

  2 - 2) enqueue

 

    스택의 가장 마지막 인덱스의 데이터를 추가한다.

 

  Queue의 dequeue와 enqueue 메서드도 스택과 마찬가지로 첫 번째 or 마지막 인덱스에서 일어나므로 시간 복잡도는 O(1)이 된다.

  반면 특정 인덱스, 즉 예를 들어 n번째 데이터에 접근하기 위해서는 dequeue 메서드를 n번 호출해야 하므로 시간 복잡도는 O(n)이 된다.

 

 

 

스택과 큐의 구현은 사실 크게 어렵지 않아서 따로 코드를 첨부하진 않아도 될 것 같다.

 

'CodeStates' 카테고리의 다른 글

IM 8일차 (Hash Table)  (0) 2021.01.20
IM 4일차 (Class)  (0) 2021.01.19
IM 4일차 (Pesudoclassical)  (0) 2021.01.15
IM 4일차 (자바스크립트에서 객체의 작동 원리)  (0) 2021.01.14
IM 4일차 (OOP와 4가지 특징)  (0) 2021.01.14

자바스크립트에서 Pesudoclassical 한 방법으로 OOP를 구현하는 방법과 ES6의 Class 키워드로 구현하는 방법을 알아보자.

 

1. Pesudoclassical

 

  1 - 1) 객체(인스턴스) 생성하기

  

    prototype 기반 객체 지향 프로그래밍에서 '클래스'의 개념을 대신하기 위해 채택된 것이 바로 '함수'다.

   

function Animal(name, speed) {
  this.name = name;
  this.speed = speed;
}

Animal.prototype.run = function() {
  console.log(`${this.name}이 ${this.speed}의 속력으로 달린다`)
}

const myDog = new Animal('doggy', 30)

    프로퍼티는 Animal에서 정의하고 메서드는 프로토타입 객체에 정의해주면 된다.

    메소드를 꼭 프로토타입 객체에 정의를 해줘야만 모든 인스턴스가 해당 프로토타입을 참조해 run 메서드를 실행할 수 있다.

 

  1 - 2) Inheritance(상속)

 

    * call, apply 함수 메서드로 부모의 프로퍼티 상속받기

      

      위 Animal 함수의 자식으로 Dog라는 함수를 만들고 프로퍼티와 메서드를 상속받아보자!

function Dog(name, speed) {
  Animal.apply(this, [name, speed]) // or Animal.call(this, name, speed)
}

    new 키워드를 통해 Dog 타입의 객체를 생성할 때 this Dog의 인스턴스를 가리키게 되어 해당 객체에 name 및 speed 속성이 생기게 된다.

 

    * Object.create 메서드로 부모의 메서드 상속받기

 

      call이나 apply를 사용하면 부모 함수의 속성을 상속받을 수 있으나, 부모 함수의 메서드는 상속받을 수는 없다.

      왜냐하면 prototype 기반 객체 지향 프로그래밍에서는 메서드가 함수의 Prototype 객체에 정의되기 때문이다.

 

      따라서 자식 함수의 Prototype 객체가 부모 함수의 Prototype 객체의 메서드를 상속받도록 코드를 작성해야 한다.

      만약 아래와 같이 자식 함수의 프로토타입 객체에 부모 함수의 프로토타입 객체를 정의한다면 어떻게 될까?

 

Dog.prototype = Animal.prototype

  

      만약 이런식으로 작성한다면 자식 함수인 Dog의 프로토타입 객체에 메서드를 추가할 때 Animal의 프로토타입 객체에도

      해당 메서드가 추가될 것이다. 왜냐하면 서로 같은 객체를 참조하고 있기 때문이다. 물론 부모의 변화도 자식에게 영향을 끼친다.

      이러한 방법은 상속이라고 볼 수 없다.

 

      따라서 우리는 Object.create() 메서드를 활용하여 부모 함수의 메서드를 자식 함수에게 상속시킬 것이다.

      Object.create() 함수는 인자로 객체를 받으며, 인자로 받은 객체를 Prototype 객체로 하는 새로운 객체를 생성해 리턴해준다.

 

function Animal(name, speed) {
  this.name = name;
  this.speed = speed;
}

Animal.prototype.run = function() {
  console.log(`${this.name}이 ${this.speed}의 속력으로 달린다`)
}

function Dog(name, speed) {
  Animal.apply(this, [name, speed]) // or Animal.call(this, name, speed)
}

 

      Dog 함수가 상속받고자 하는 Animal 부모 함수의 메서드는 Animal.prototype 객체에 존재한다.

      따라서,Animal.prototype 객체를 Object.create() 함수의 인자로 주어, 그 객체를 Prototype 객체로 하는 새로운 객체 B를 생성하고

      이를 Dog 함수의 Prototype 객체로 설정해주는 다음과 같은 코드를 작성하면,

Dog.prototype = Object.create(Animal.prototype);

 

      Dog의 Prototype 객체의 __proto__ 속성이 Animal.prototype 객체를 가리키게 되면서 Animal.prototype 객체와 Dog.prototype

      객체 사이에 계층 구조가 생기게 되며, 이를 통해 부모-자식 관계가 생성되게 된다.

 

      이제 Dog 의 인스턴스가 run 메서드를 호출하면, 자바스크립트는 먼저 해당 인스턴스에서 run 메서드를 찾아보고, 없다면     Object.create로 생성된 Dog의 Prototype 에서 찾아보고, 또 없다면 Dog.prototype의 __proto__ 속성이 가리키는 Animal.prototype

 의 객체에서 찾아보고 그래도 없다면 계속 상위 prototype 객체로 거슬러 올라갈 것이다.

      

      다만 우리가 주의할 점이 한 가지 있다.

 

    * Dog.prototype 객체의 constructor 를 Dog 함수로 변경하기

 

      앞서 Object.create(Animal.prototype) 메서드의 결과를 Dog.prototype 객체에 할당해주었는데 여기서 한 가지 문제점이 발생한다.

      이전 포스트에서 프로토타입 객체에 정의된 constructor 함수는 기존 함수 자체를 바라보고 있다고 했다.

      따라서 Dog.prototype.constructor === Dog 여야 한다.

 

      그러나 지금 같은 경우 Dog.prototype.constructor === Animal 이다.

      우리가 Animal 객체를 Prototype 객체로 가지는 새로운 객체를 만들 때 Object.create() 함수 호출 시 Dog 함수에 대한

      아무런 정보를 주지 않았기 때문에, 자바스크립트는 새로 만들어진 객체의 constructor에 무슨 값을 넣어줘야 하는지 모른다.

 

  따라서 Object.create()는 인자로 들어온 Animal.prototype의 constructor의 값을 그대로 복사해 새 객체의 constructor 값으로 설정해주며, 이 때문에 새 객체의 constructor가 Animal.prototype 객체의 constructor가 가리키는 Animal 함수를 가리키게 된 것이다.

 

    해결 방법은 단순하다.

Dog.prototype.constructor = Dog;

 

     다음과 같이 수동으로 바꿔주면 된다.

 

'CodeStates' 카테고리의 다른 글

IM 4일차 (Class)  (0) 2021.01.19
IM 7일차 (Stack, Queue)  (0) 2021.01.19
IM 4일차 (자바스크립트에서 객체의 작동 원리)  (0) 2021.01.14
IM 4일차 (OOP와 4가지 특징)  (0) 2021.01.14
IM 3일차 (ESLint와 rules)  (0) 2021.01.13

자바스크립트에서 객체의 작동 원리를 알아보자! 또한 작동 원리를 알기 위해 우리는 잠시 ES6의 Class 문법 이전으로 돌아갈 것이다.

 

1. 객체의 생성

 

let obj = {}

let obj = new Object()

//빈 객체를 선언과 동시에 할당하는 방법
//두 방법은 같은 결과를 초래한다.

  

  ES6 이전의 자바스크립트 세계에선 Class라는 개념이 없었다. 그렇다면 객체를 생성하기 위한 new Object()에서 Object는 무엇일까?

  여기서 Object는 바로 함수이다. 즉 ES6 이전에는 OOP를 함수로 구현했음을 짐작할 수 있다.

 

  함수는 클래스와 비슷하다. 함수 내부에서 여러 변수들과 함수를 정의할 수 있으며 여러 번 호출할 수 있기 때문이다.

  다음의 예시를 살펴보자.

 

function Animal(name, speed) {
  this.name = name;
  this.speed = speed;
  
  this.run = function () {
      console.log(`${this.name}가 ${this.speed}km/h의 속력으로 달립니다!`);
    }
  }
  
  const myDog = new Animal('doggy', '10');

 

  위와 같은 코드를 통해 Animal 타입의 myDog 라는 객체를 생성할 수 있다.

  그런데 위와 같은 코드는 하나의 문제를 가지고 있다.

  클래스 기반 객체 지향 프로그래밍에서 클래스에 메서드를 정의하면, 해당 클래스 타입의 모든 객체들은 하나의 메서드를 공유하게 된다. 

 

  하지만, 위와 같은 자바스크립트 코드는 다르다.

  이 코드는 Car 타입 객체가 생성될 때 마다 Drive라는 변수를 생성하고, 이 변수에 익명 함수를 저장하는 형태로 동작한다.

  즉, 객체가 생성될 때 마다 새로운 익명 함수가 생성되어 Drive에 저장되고 메모리 낭비가 심할 것이다.

  무엇보다 진정한 의미에서의 객체 지향을 구현한 것이 아니게 된다.

 

  자바스크립트에서 동일한 타입의 모든 객체가 하나의 메서드를 공유하도록 코드를 구현하려면, 위의 Animal 함수 정의에서 run 메서드 부분을 아래와 같이 고쳐야 한다.

 

function Animal(name, speed) {
    this.name = name;
    this.speed = speed;
}

Animal.prototype.run = function () {		<= 변경된 부분
    ...
}

const myDog = new Car("doggy", 10);

 

  앗 갑자기 생소한 것이 등장했다. prototype? 이 의미하는 것은 무엇일까

 

 

 

2. prototype

 

  prototype의 사전적 의미로는 원형이라는 뜻을 가지고 있다.

  위의 Animal 함수의 run 메서드를 모든 Animal 타입 객체들이 공유하게 만들기 위해 Animal.prototype이라는 곳에 run 메서드를 정의했다.

 

  Animal prototype이라는 변수는 모든 Animal 타입 객체들의 기준이 되는 단 하나의 '원형' 객체를 가리킨다.

  우리가 아래 코드처럼 Animal 함수를 정의하면, Animal 함수에는 run이라는 메서드가 존재하지 않는다.

 

 

 

  대신 Animal.prototype을 확인해보면 run 메서드가 존재함을 확인할 수 있다.

 

 

  자바스크립트는 myDog.run()을 통해 메서드를 호출할 때, 해당 객체에 Drive 메서드가 존재하지 않는다면 그 객체의 prototype으로 이동하여 run 메서드가 존재하는지 확인하고, 존재한다면 원형 객체의 run 메서드를 호출한다. 이런 방식으로 동작하기 때문에 Animal 타입의      모든 객체들이 동일한 원형 객체의 run 메서드를 호출하게 되는 것이다.

 

  그런데 원형 객체라는 것은 언제 만들어진 것이고, Animal.prototype이라는 건 어떻게 원형 객체를 가리키게 된 것일까?

  우리는 Animal에 prototype이라는 이름의 변수를 선언한 적도 없으며 Animal의 원형 객체라는 것도 만든 적이 없는데 말이다.

 

  자바스크립트에서는 우리가 어떤 함수를 정의하든 간에 해당 함수에 대한 Prototype 객체를 자동으로 생성해주며, 그 함수에 대해 '함수. prototype'이라는 변수도 생성한 후 이 변수가 Prototype 객체를 가리키도록 연결해준다. 지금 당장 콘솔에 가서 확인해보라.

 

  그냥 일반적인 함수 호출을 사용하기 위해 함수를 정의했다고 하더라도 자바스크립트는 무조건 해당 함수에 대한 Prototype 객체를 생성한다.

 

 

 

3. Constructor(생성자)

 

  constructor 함수는 클래스 기반 객체 지향 프로그래밍에서도 등장하는 익숙한 개념인 바로 그 생성자로,

  우리가 객체 생성을 요청할 때 호출되어 실제 객체를 만드는 역할을 하는 함수이다.

  즉 new Animal()라는 코드를 호출해 Animal.prototype.constructor 함수가 자동으로 호출되어 객체를 생성해준다.

 

  사실 자바스크립트에서는 Prototype 객체의 constructor가 기존 함수 자체를 가리키기 때문에, Animal.prototype.constructor는 function Animal(name, speed)를 가리킨다.

  

  단지, new 키워드가 함수 내부에서 사용한 this를 실제로 생성된 instance를 가리키도록 만들어주므로, 자바스크립트의 객체 생성에 있어 진짜 중요한 역할은 생성자가 아니라 new 키워드가 처리해준다고 볼 수 있다.

 

 

 

4. __proto__

 

  constructor 메서드는 오직 '함수의 Prototype 객체'만이 가진다.

  하지만 __proto__는 자바스크립트의 '모든 객체'에 대해 자동으로 추가되는 속성이다.

  

  그렇다면 이 __proto__에는 어떤 값이 담겨있을까?

 

  위 글에서 Animal.prototype이 가리키는 Prototype 객체에 Drive 함수를 정의하면, Animal 타입의 모든 객체들이 Prototype 객체의 run 함수를 사용하게 된다고 했었다.

  하지만 자바스크립트가 myDog.run()라는 코드를 보고 Prototype 객체의 run 메서드를 호출하려면, myDog 객체에서 Prototype 객체에 참조할 수 있어야 한다.

이를 위해 자바스크립트는 모든 객체의 인자로 Prototype 객체를 가리키는 __proto__라는 변수를 정의해준다.

  

  즉 위 예제에서 myDog.__proto__ === Animal.prototype 인 것이다.

 

  따라서, myDog.run()라는 코드가 실행되면 자바스크립트는 다음과 같은 과정을 거쳐 Prototype 객체의 run 메서드를 호출한다.

  1. myDog 객체에 run 메서드가 있는지 확인한다.

  2. myDog 객체에 run 메서드가 없으면, Prototype 객체에 해당 메서드가 존재하는지 확인하기 위해 __proto__ 변수가 가리키는 객체로 이동한다.

  3. Prototype 객체에 run 메서드가 존재한다면, Prototype 객체의 run 메서드를 호출한다.

 

 

5. Prototype chain

 

  만약 Animal.prototype에 run 메서드를 정의하지 않아서, Prototype 객체에도 메서드가 존재하지 않는다고 가정해보자.

  그렇다면, 자바스크립트는 Animal 함수의 Prototype 객체에서 탐색을 종료할까?

 

  정답은 아니다. 자바스크립트에서 모든 객체는 최상위 객체로 Object라는 객체를 가진다.

  Prototype 객체도 결국 객체이므로 최상위 객체로 Object 객체를 가진다.

  따라서 Prototype 객체인 Animal.prototype의 __proto__ 속성은 아래와 같이 최상위 객체인 Object의 Prototype 객체를 가리키게 된다.

 

 

 

  이처럼 Prototype 객체들이 __proto__ 속성을 통해 연결되는 구조를 'Prototype Chain'이라는 용어로 부른다.

  자바스크립트는 어떤 함수의 Prototype 객체에서 원하는 메서드를 찾지 못한다면 해당 Prototype 객체의 __proto__ 속성이 가리키는 부모 Prototype 객체로 이동한다. 즉 찾을 때까지 계속 거슬로 올라가는 것이다.

 

  이 작업은 Object 함수의 Prototype 객체에 도달할 때까지 반복되며, Object.prototype 객체는 최상위 객체이므로 __proto__ 속성의 값이 null이기 때문에 더 이상 이동할 수 있는 부모 Prototype 객체가 존재하지 않아 작업을 중단한다.

 

 

 

후.. 이해하는데 너무 어려운 주제였다. 블로깅 내용의 80%는 다음의 블로그를 참조했다!

 

 

 

출처 : velog.io/@piecemaker/3.-%EC% 9E%90% EB% B0%94% EC% 8A% A4% ED%81% AC% EB% A6% BD% ED% 8A% B8% EC%97%90% EC%84%9C-%EA% B0% 9D% EC% B2% B4% EA% B0%80-%EB% 8F%99% EC% 9E%91% ED%95%98% EB% 8A%94-%EB% B0% A9% EC% 8B%9D-%EC% 9D% B4% ED%95% B4% ED%95%98% EA% B8% B0

 

 

 

'CodeStates' 카테고리의 다른 글

IM 7일차 (Stack, Queue)  (0) 2021.01.19
IM 4일차 (Pesudoclassical)  (0) 2021.01.15
IM 4일차 (OOP와 4가지 특징)  (0) 2021.01.14
IM 3일차 (ESLint와 rules)  (0) 2021.01.13
IM 2일차 (ES6 문법)  (0) 2021.01.12

1. OOP(Object Oriented Programming)

 

  어떤 공통적인 특징을 가지고 있는 것에 각기 다른 특징을 부여해 하나의 물체를 만드는 프로그래밍이라고 할 수 있다.

  예를 들어 A와 B가 함께 저녁 식사를 하려고 한다. A가 B에게 뭐 먹을 거냐고 물었다. B는 '고기'라고 말했다.

  바로 여기서 이 '고기'가 공통적인 어떠한 것이다. A가 B에게 무슨 고기를 먹을 건지 구체적으로 대답해달라고 했다.

  B는 '소고기'라고 답했다. 여기서 '소고기'가 고기는 고긴데 '소'라는 특징을 부여해 만들어진 물체라고 할 수 있다.

 

  그리고 객체 지향 프로그래밍에서 공통적인 어떤 것을 'class'라고 하고 그것으로부터 추가적인 특성을 부여받은 것을 'instance'라고 한다.

  따라서 위 예제에서는 '고기' -> 'class', '소고기' -> 'instance'가 될 것이다.

 

 

 

2. 프로퍼티와 메소드

 

  클래스 내에서 선언된 공통적인 변수를 프로퍼티라 하고 공통적인 어떤 기능을 할 수 있는 함수를 메서드라 한다.

  여기서 '공통적인'이라는 의미가 중요하다. 공통적이라는 말은 해당 특징과 기능을 모두 가지고 있다는 의미와 같다.

  따라서 instance가 class의 프로퍼티와 메서드에 관한 모든 것을 갖고 있다고 봐도 무방할 것이다.

 

 

 

3. 객체 지향 프로그래밍의 4대 특성

 

  객체 지향 프로그래밍 기법은 대표적인 4가지 특징이 있고 이 특징을 코드에 적용시키기 위해 프로그래밍 언어에 도입되었다고 할 수 있다.

  이 특성들은 코드를 더 정돈되고 간결하게, 그리고 보다 안전하게 만들어준다.

 

  3 - 1) 캡슐화(Encapsulation)

 

    캡슐화란 연관된 변수들과 함수들을 하나의 '클래스'라는 캡슐로 묶어 제공함으로써, 개발자는 미리 정의된 클래스로부터 하나의 객체를 생성하기만 하면 클래스가 제공하는 모든 변수 및 메서드들을 사용할 수 있게 된다.

 

    즉 어떤 특정 객체를 정의하기 위해서 해당 객체에 관한 변수와 메서드를 매번 만들 필요가 없단 말이다!

 

  3 - 2) 정보 은닉(Information Hiding)

 

    자바스크립트를 포함한 보통의 프로그래밍 언어에서는 기본적으로 외부에서 객체의 모든 변수들과 메서드들에 자유롭게 접근할 수 있는데, 이 자유로운 접근이 문제가 될 수 있다.

 

    객체 지향 프로그래밍에서는 접근 제어 자라는

    접근 제어자는 클래스의 프로퍼티 및 메서드에 대해 적용될 수 있고, 프로그래밍 언어에 따라 지원되는 접근 제어자의 종류가 다르나 가장 대표적인 두 가지는 다음과 같다.

 

  • public: 외부에서 해당 변수 및 메서드에 접근할 수 있다. 대부분의 경우 접근 제어자가 명시되어 있지 않다면 기본값으로 public이다.
  • private: 외부에서 해당 변수 및 메소드에 접근할 수 없으며 클래스 내부에서만 사용할 수 있다.

  또한 보안의 관점에서 본다면 정보 은닉이라고 할 수도 있겠지만, 이러한 정보 은닉의 특성은 다른 관점에선 추상화라고 할 수 있다.

 

  추상화(Abstraction)란 내부의 복잡한 로직을 사용자가 편하게 쓸 수 있도록 인터페이스를 구성한 것이라고 볼 수 있다.

  예를 들어 내가 친구에게 전화를 건다고 생각해보자. 전화 연결이 대충 어떻게 이루어지는지는 알고 있지만 구체적으로 정확하게

  어떤 로직에 의해서 서로 전화가 되는 것인지는 전문가가 아니라면 잘 알지 못한다.

 

  하지만 우리는 단지 핸드폰에 상대방의 핸드폰 번호를 누르고 통화 버튼만 누르면 상대방과 전화를 할 수 있음을 알고 있다.

  이러한 복잡한 것을 단순하게 구현하는 것이 추상화이다.

 

  클래스의 접근 제어자를 통해서 접근할 수 있는 것이 있고 접근할 수 없는 것이 있을 텐데 바로 위 예시에서 접근할 수 있는 것은

  전화번호를 입력하는 것과 통화 버튼을 누르는 것일 테고 그 외의 모든 것은 접근할 수 없는 것이 될 것이다.

 

  3 - 3) 상속(Inheritance)

 

    상속은 위의 두 가지 특성보다는 이해하기에 더 쉽다고 생각한다.

    말 그대로 상속이란 부모 클래스에서 정의된 속성이나 메서드들을 물려받을 수 있다는 것이다.

    

    어 그럼 인스턴스가 클래스의 자식인가요? 전혀 아니다 인스턴스는 해당 클래스의 복제품이지만 각기 다른 특성을 가지고 있는 것이고

    상속 클래스는 부모 클래스의 특성을 그대로 물려받으면서 상속받은 자식만의 추가적인 특성을 가지고 있는 것이라고 할 수 있다.

 

    사실 블로깅 하다 보니 맨 위의 고기 예제를 통해서 설명할 때 조금 헷갈리게 설명한 거 같긴 하다...

    스마트폰으로 예를 들어보자.

 

    가장 상위 class를 그냥 스마트폰이라고 하자.

    그리고 자식 class로는 아이폰 계열과 갤럭시 시리즈가 있을 수 있다.

    

    두 개의 자식 class는 스마트폰의 공통적인 프로퍼티와 메서드를 모두 사용할 수 있고 본인들만의 프로퍼티와 메서드가 추가되는 것이다.

    아이폰은 애플의 제품이다, 갤럭시는 삼성의 제품이다 등이 각 자식 class만의 고유한 특성인 것이다.

    또한 아이폰에는 다양한 시리즈가 있을 것이다 그러한 각 시리즈(6, 7, 8, 10, 12 등)가 아이폰 class의 고유한 자식이 될 것이다.

 

  3 - 4) 다형성 (Polymorphism)

 

    말 그대로 다양한 특성을 가질 수 있다는 말이다.

    다형성은 상속과 관련이 있다. 부모 클래스로부터 상속된 자식 클래스는 프로퍼티와 메서드를 물려받는다고 했다.

    맞는 말이다. 반대로 생각하면 물려받는 프로퍼티와 메서드는 절대로 수정할 수 없는 것인가?라고 생각할 수 있는데 결론은 아니다.

 

    예를 들어 빵이라는 클래스가 있다고 해보자. 그리고 빵 클래스에는 먹다는 메서드가 있다. 먹다는 메서드를 호출하면

    맛있다는 문장이 출력된다고 가정한다. 그리고 빵 클래스의 자식 클래스로 딱딱한 빵과 부드러운 빵이 있다.

  

    나는 딱딱한 빵에서 먹다는 메서드를 호출하면 이 빵은 식감은 딱딱한데 맛있다 라고 출력하고 싶고

    부드러운 빵에서 먹다는 메서드를 호출하면 이 빵은 식감도 부드럽고 맛있다고 출력하고 싶다.

 

    이럴 때 자식 클래스의 먹다는 메서드가 부모 클래스의 먹다는 메서드를 덮어 씌운다라고 해서

    메소드 오버 라이딩(method overriding)이라고 한다. 덮어 씌운다는 의미를 무조건 부모 클래스의 먹다는 메서드의 출력인

    '맛있다'가 있어야 된다는 것을 의미하는 게 아니다. 그냥 자식 클래스에서 똑같은 메서드를 재정의 할 수 있다고 받아들이면 된다.

 

    재정의 한다는 것 자체가 여러 가지를 표현할 수 있다는 의미이고 이것이 곧 다형성을 의미하는 것이다.

    

 

 

4. 요약

 

  4 - 1) OOP의 개념 : OOP란 어떤 공통적인 특징을 가지고 있는 것에 각기 다른 특징을 부여해 하나의 물체를 만드는 프로그래밍이다.

 

  4 - 2) OOP의 4가지 특징

 

  1. 캡슐화: 관련된 모든 속성 및 메서드들을 하나의 클래스에 모은다.
  2. 정보 은닉: 외부로 공개해서는 안 되는 정보들을 접근 제어자를 통해 숨긴다.
  3. 상속: 자식 클래스가 부모 클래스의 모든 것을 받는다.
  4. 다형성: 자식 클래스에서 부모 클래스의 메서드 재정의한다.

 

 

참고 : velog.io/@piecemaker/2.-%EA% B0% 9D% EC% B2% B4-%EC% A7%80% ED%96% A5-%ED%94%84% EB% A1% 9C% EA% B7% B8% EB% 9E%98% EB% B0% 8D% EC% 9D%98-4% EB% 8C%80-%ED% 8A% B9% EC%84% B1

 

 

 

 

얼마 전에 인터넷을 지역 인터넷으로 바꾸었더니 실시간 스트리밍이 자꾸 끊기는 현상이 발생하고 있다..

페어와 원격으로 의사소통해야 하는데 중간중간 자꾸 줌이 튕겨서 너무 미안했다 ㅜㅜ 

 

오늘은 프리 코스때 제출했던 과제를 ES6 문법으로 리팩터링 하고 문법 에러나 일정한 코드 스타일을 강제하는 esLint 모듈을 사용해보았다.

 

리팩터링 관련해선 크게 언급할 건 없을 듯하다. 그저 ES6 이후 문법을 계속 쓰면서 익숙해져야 할 것 같다.

그래서 ESLint의 설치와 적용 및 활용 방법에 대해 간단하게 정리하려고 한다.

 

1. ESLint 란?

 

  ESLint는 JavaScript 코드에서 발견된 문제점을 식별하고 보고하는 도구로, 코드의 일관성을 높이고 버그를 방지하는 모듈이다.

 

2. ESLint 설치, 룰

 

  2 - 1) 설치 명령어

 

    npm과 yarn 무엇을 사용하는 지에 따라 명령어를 아래 둘 중 하나로 선택하면 된다.   

npm install eslint --save-dev

# or

yarn add eslint --dev

 

    해당 명령어로 eslint를 다운하고 반드시 다음 과정을 거쳐야 한다.

npx eslint --init

# or

$ yarn run eslint --init

   

    위 명령어는 configuration file을 초기화하는 명령어다. 해당 명령어를 통해 eslint configuration file이 생긴다.

    configuration file이 생기면 아래의 명령어를 통해 eslint를 실행할 수 있다.

$ npx eslint yourfile.js

# or

$ yarn run eslint yourfile.js

 

 

 

  2 - 2) configuration file rules

 

    eslint는 문법의 에러나 코드의 일관성을 요구하는 툴이므로 어떠한 것을 에러로 낼지 아닐지가 중요할 것이다.

    eslint에서 어떤 부분을 에러로 볼 것인지 어떠한 툴을 쓰고 있는지 알려주려면 configuration file의 rules를 수정하면 된다.

    따라서 해당 파일에서 우리가 가장 주목해야 할 부분은 rules일 것이다.

 

    먼저 rules란 eslint에서 어떠한 것을 에러로 처리할 것인가 에러로 처리하지 않을 것인가에 관한 설정이다.

    아 참고로 configuration file이 초기화 될 때 "extends": "eslint:recommended"와 같은 설정이 자동으로 되어 있을 것이다.

    이 설정이 적용되어 있으면 checkd rules에 한해 eslint에서는 기본적으로 error를 낸다.

    

    eslint.org/docs/rules/ 에 가면 수 많은 룰 중에 체크된 것도 있고 아닌 것도 있고 또 wrench mark가 표시된 룰도 있는데

    위에서 언급했듯 체크가 되어있으면 기본적으로 eslint를 실행했을 때 에러를 낸다는 것이다.

 

    해당 에러를 안 내고 싶다면 "해당 룰 이름" : "off"를 rules에 추가해주면 된다.

    wrench의 의미는 eslint로 코드를 수정할 때 명령어의 옵션으로 --fix 값을 주면 해당 에러를 가지고 있는 모든 코드를 한 번에 고칠 수 있는 룰을 의미한다.

    따라서 그러한 룰은 일일이 수동으로 고칠 필요가 없다는 것이다!

    룰에 관해선 여기까지 설명하면 충분할 것 같다. 많은 룰들이 있고 그것을 적용할지 안 할지는 본인에게 달려있다.

 

    

  

오늘 배운 것 : 화살표 함수, 구조 분해 할당, 실행 콘텍스트에 따른 this의 5가지 값, call/apply/bind 메서드

 

1. 화살표 함수

 

  프리 코스 때부터 의도적으로 쓸려고 노력해서 크게 어렵지 않았다. 무난하게 과제를 수행할 수 있었음.

  코드가 길어지면 {}가 필요한데 이때 명시적으로 return을 해줘야 한다는 점만 주의하면 됨!

 

 

 

2. 구조 분해 할당

 

  rest/spread syntax와 함께 중첩된 객체를 구조 분해하는 경우를 제외하곤 괜찮았다.

  또한 하나의 객체가 다른 객체에서 rest parameter로 들어가 있는 경우 만약 같은 key를 가진 property가 있다면

  뒤에 나온 property가 앞에 있는 property를 덮어 씌우게 된다!

 

 

 

3. this

 

  조금 헷갈리긴 했지만 그래도 괜찮았다. 익숙해지면 괜찮을 것 같다. 그래도 개념은 다시 한번 정리하고 가야 할 것 같다.

 

  this는 함수 실행 시 호출(invocation) 방법에 의해 결정되는 특별한 객체다.

  함수 실행시 결정되므로, 실행되는 맥락(execution context)에 따라 this는 다르게 결정된다.

 

  3 - 1) 함수 실행에 따른 this의 5가지 바인딩 패턴

 

  • Method 호출 : 부모 객체 (실행 시점에 온점 왼쪽에 있는 객체), 중첩된 객체가 있더라도 바로 본인의 부모를 가리킴.
  • new 키워드를 이용한 생성자 호출 : 이 때는 new 키워드로 만들어진 instance가 this가 가리키는 값이 된다.
  • . call 또는. apply 호출 : 첫 번째 인자로 전달된 객체, 즉 사용자가 명시적으로 this 값을 주어야 함!
  • Global : 브라우저의 경우 -> window (strict mode에서는 undefined) 객체, node.js -> module.exports
  • function 호출 : 브라우저 -> window (strict mode에서는 undefined) 객체, node -> global

  global, function 호출의 경우 애초에 this를 사용하지 않을 것을 권고.

 

 

 

4. .call/.apply/.bind 메서드

 

  .call, .apply, .bind는 this값을 명시적으로 지정하고 싶을 때 사용한다.

  .call과 .apply는 매우 유사하다. 지정된 this 콘텍스트와 추가적인 인수를 사용하여 함수를 호출한다.

  .call과 .apply의 유일한 차이점은 .call은 인수를 하나씩 전달해야하며 .apply는 인수를 배열로 취한다는 것이다.

 

  예시를 통해 알아보자.

 

  4 - 1) .call, .apply

const book = {
  title: 'Brave New World',
  author: 'Aldous Huxley',
}

function summary() {
  console.log(`${this.title} was written by ${this.author}.`)
}

summary()

    summary 함수와 객체 book은 어떠한 connection이 없다.

    때문에 summary를 호출하면 전역 객체에서 해당 속성을 찾을 때 undefined가 나타날 것이다.

 

    그러나 call 및 apply를 사용하여 함수에서 객체 book의 this 콘텍스트를 호출할 수 있다.

summary.call(book)
// or:
summary.apply(book)

//"Brave New World was written by Aldous Huxley."

    이러한 방법을 적용하면 이제 객체와 함수가 연결된다.

    그리고 this 값은 우리가 명시적으로 전달해준 객체 book이 된다.

 

    두 개의 메서드의 차이점은 위에서 언급했듯이 call은 추가적인 인수를 하나씩 받는 반면 apply는 배열에 모두 담아 전달해야 한다.

 

 

 

  4 - 2) .bind

 

    call과 apply는 모두 일회성 사용 방법이다.

    this 콘텍스트를 사용하여 메서드를 호출하면 그대로 유지되지만 원래 함수는 변경되지 않는다.

    때로는 다른 객체의 this 콘텍스트와 함께 메서드를 반복해서 사용해야 할 수 있다.

    이 경우 bind 메서드를 사용하여 명시적으로 바인딩된 새로운 함수를 만들 수 있다.

 

    마찬가지로 예시를 통해 알아보자.

const braveNewWorldSummary = summary.bind(book)

braveNewWorldSummary() // Brave New World was written by Aldous Huxley.

const book2 = {
  title: '1984',
  author: 'George Orwell',
}

braveNewWorldSummary.bind(book2)

braveNewWorldSummary() // Brave New World was written by Aldous Huxley.

    이 예에서는 braveNewWorldSummary를 호출할 때마다 항상 바인딩된 원래 this 값을 반환한다.

    새로운 this 콘텍스트를 바인딩하려는 시도는 실패하므로 항상 바인딩된 함수를 신뢰하여 예상한 this 값을 반환할 수 있다.

    

 

 

*참고 : dev.to/digitalocean/understanding-this-bind-call-and-apply-in-javascript-dla

1. NVM

 

  Node Version Manager라고 한다.

  NVM을 통해 간단한 명령어로 node를 설치하고, 다양한 node version을 손쉽게 옮겨 다닐 수 있다. 

  NVM 역시 하나의 프로그램이므로 설치해야 한다.

  

  1 - 1) NVM version 확인

$ nvm ls

 

  1 - 2) NVM으로 원하는 버전의 node.js 다운로드하기

$ nvm install 10.13.0

 

  1 - 3) 다른 노드 버전 사용하기

$ nvm use (사용하고 싶은 node version : use 명령어 전에 해당 node version이 설치되어있어야 합니다.)
ex) nvm use 12.13.0

 

 

 

2. package.json

 

  2 - 1) NPM

 

    package.json에 들어가기에 앞서 NPM이 무엇인지 간단하게 알아보자.

    NPM은 Node Package Manager로 필요한 모듈을 다운로드할 수 있는, 모듈들이 모여있는 모듈 스토어다.

 

    모듈은 직접 만들 수도 있지만 NPM에 상당한 고수들이 이미 잘 만들어놓은 모듈들이 있다.

    그리고 그러한 모듈은 실력이 부족한 개발자가 직접 만든 모듈보다도 더 성능이 우수하고 버그가 적게 일어날 가능성이 높다.

 

    내가 잘 만들어 놓은 모듈이 매주 몇 백만의 다운로드를 기록한다면 개발자로서 얼마나 뿌듯할까..

    어쨌거나 그러한 모듈들이 모여 하나의 프로젝트가 만들어지게 된다.

 

    또한 NPM은 node 모듈을 사용하는 프로젝트에서 npm이라는 키워드는 하나의 명령어처럼 사용되기도 한다.

    npm start처럼, 프로젝트를 실행시킬 때 npm 키워드를 사용하기도 한다.

 

  2 - 2) package.json

 

  package.json에는 이 프로그램을 실행시키기 위해 필요한 모듈이 무엇인지, 프로그램을 실행시키는 방법, 테스트하는 방법 등이 명시되어 있다.

  그러나 이 프로그램을 실행시키기 위해 필요한 실제 모듈은 node_modules이라는 폴더에 다 들어가 있다.

  package.json에는 어떤 모듈인지만 적혀 있다. 즉, 전자제품을 보러 갔을 때 제품 카탈로그가 바로 package.json이다.

  카탈로그만 보면 어떤 제품이 있는지 파악할 수 있는 것처럼 package.json만 보면 어떤 모듈이 들어가 있는지를 알 수 있다.

 

  즉, A가 B가 만든 모듈을 사용하려고 하는데 B가 만든 모듈에 있는 파일을 전부다 전달받는 게 아니라 B는 단지 package.json에

  해당 모듈에 필요한 모듈만 적어주고 A는 npm install 명령어를 통해 package.json에서 필요하다고 하는 모듈을 다운로드하면 되는 것이다.

 

  필요한 모듈까지 모두 넘겨주는 것은 전달해야 하는 파일도 너무 많거니와 필요가 없는 일이다.

  사용하는 사람이 직접 다운로드하여서 쓰라고 하면 되기 때문이다.

 

 

 

3. Simple Git work flow

 

  페어와 공통 과제를 fork -> clone 하여 각자 GitHub에 있는 원격 저장소와 로컬 저장소를 생성했다.

  

  먼저 git remote add 명령어를 통해 서로의 로컬 저장소를 상대방의 원격 저장소와 연결했다.

  그 후 각자 한 번씩 git add, commit 명령어를 통해 새로운 버전을 만들고 상대방은 해당 버전을 pull 명령어를 통해 최신 버전을 

  각자의 로컬 저장소로 당겨왔다.

 

  여기서 주의할 점은 나의 원격 저장소의 별명이 아니라 remote add를 했을 때 설정했던 상대방의 

  원격 저장소의 별명을 적용해야 한다. 왜냐하면 상대방의 원격에서 pull을 해야 하기 때문이다.

 

  또한 서로 똑같은 파일의 똑같은 코드 라인을 수정하여 각자의 원격에 push 하고 그 후 pull 명령을 통하여 일부러 conflict가 나는 

  상황도 만들어보았다. 그 후에 VS code에서 수동으로 conflict를 해결해 주었다.

 

  마지막으로 git branch를 만들고 해당 브랜치로 checkout을 통해 이동을 시도했으며 내가 만든 브랜치를 페어가 pull 하는 것까지

  해보았다. 마찬가지로 주의할 점은 상대방의 master branch가 아니라 다른 branch를 pull 해야 해당 브랜치가 받아와 진다.

 

  끝으로 혼자 공부하면서는 SourceTree를 많이 사용했는데 페어를 하면서는 CLI로 git을 활용하면서 깃과 조금 더 친해진 거 같다!

  앞으로도 되도록이면 CLI를 사용해야겠다.

'CodeStates' 카테고리의 다른 글

IM 4일차 (Pesudoclassical)  (0) 2021.01.15
IM 4일차 (자바스크립트에서 객체의 작동 원리)  (0) 2021.01.14
IM 4일차 (OOP와 4가지 특징)  (0) 2021.01.14
IM 3일차 (ESLint와 rules)  (0) 2021.01.13
IM 2일차 (ES6 문법)  (0) 2021.01.12

+ Recent posts