header

Day 2 - 2022/10/18

💡 새롭게 알게된 점

함수형 프로그래밍

함수형 패러다임

프로그램은 순차, 분기, 반복, 참조로 구성되고, 패러다임은 이 4가지 요소를 어떻게 이용할 것인가를 다룬다.

  • 객체지향 추상화의 최소 단위가 객체인 것처럼 함수형은 함수가 최소 단위 → 재사용성이 높다!
  • 불변성을 지향하기에 동작 예측이 쉽고 사이드 이펙트를 방지 → 쓰레드 등을 통한 동시성 문제를 해결할 수 있다.
  • 객체지향은 제어 흐름의 간접적인 전환에 부과되는 규율이다.
  • 함수형은 변수 할당에 부과되는 규율이다.

함수형 프로그래밍의 장단점

장점

  • 상태가 없기 때문에 사이드 이펙트가 없다.
  • 함수 단위로 나눠지기 때문에 재사용성이 높다.
  • 함수의 조합을 통해 코드가 짧고 간결하다.

단점

  • 상태가 없다는 뜻은 변수 조작이 안된다는 뜻이므로 다른 방법(수정 후 복사한 다음 기존 값과 교체)을 사용해야 한다. → 쓸데없는 메모리와 성능 사용하는 문제점을 가진다.
  • 높은 재사용성을 위해 함수를 작게 쪼개야 한다. → 쪼개진 함수가 많아져서 복잡성 증가하는 문제점이 발생한다.
  • 코드를 짧고 간결하게 작성하기 위해 높은 숙련도를 요구한다.


선언형 프로그래밍

선언형 프로그래밍이란 무엇을 해결해야 할지에 집중하고 해결 방법은 컴퓨터에게 위임하는 방법이다.

Date Flow(Stateless, Recursion, Pipe) 방식으로 코드 작성 시 데이터의 제어 없이 필요한 함수만 조합하여 문제 해결이 가능하다.

[1, 2, 3, 4, 5]
	.filter((item) => item % 2 === 0)
	.forEach((itme) => console.log(item));


멀티 패러다임

그렇다면 객체지향과 함수형으로 나눠서 각각 따로 사용해야 할까?

각각의 장점을 극대화하여 사용하기 위해 객체 지향과 함수형으로 나눌 필요가 없다. → JavaScript는 멀티 패러다임이 가능하기 때문!


객체지향과 프로토타입

객체지향

객체지향이란 객체 위주로 설계하고 프로그래밍하는 패러다임이다.

객체지향의 객체는 현실에 있는 것을 추상화한 것이다. (= 추상화의 최소 단위가 객체)

(추상이란? 사물이 지니고 있는 여러 측면 중 특정한 부분만 추출하여 보는 것)

객체지향의 오해

  1. C언어에서 객체지향 프로그래밍이 불가능하다.
    • Nope! 객체지향은 패러다임일 뿐 언어와는 관계가 없다.
    • 클래스가 없는 JavaScript에서는 프로토타입을 통해 객체지향을 표현할 수 있다.
  2. 패러다임에 우위가 있다. (객체지향 > 절차지향)
    • Nope! 만들어야 하는 프로그램에 따라 다르다. 간단한 프로그램은 절차지향 프로그래밍이, 복잡한 프로그램은 객체지향 프로그래밍이 효율적이다.

프로토타입

JavaScript에서 객체는 클래스 기반 언어처럼 속성과 행위를 정의할 수 있기 때문에 객체만 활용해도 객체지향 프로그래밍이 가능하다.

그렇다면 프로토타입이 왜 필요할까?

두 개의 인스턴스를 생성할 때 두 객체 모두 각각 메서드가 따로 정의되는데, 이 경우 같은 내용인데도 생성된 것이므로 메모리가 낭비될 수 있다! (예: getName, setName)

프로토타입을 이용하면 상위 객체를 참조할 수 있고 객체를 이용하여 새로운 객체를 추가적으로 만들어 나갈 수 있다.

프로토 타입 사용의 예시

function Person(name, company, move) {
	this.name = name;
	this.company = company;
	
	Person.prototype.getName = function () {
		return this.name;
	};
	
	Person.prototype.setName = function (name) {
		this.name = name;
	};
} 

프로토 타입을 더 잘 사용하려면?

  1. 상속 흉내내기 1 - 부모 객체를 이용하여 프로토타입 함수 정의하기
    • 엄밀히 따지면 상속이 아니라 상위 객체에서 하위 객체를 조금 더 잘 만드는 방법이다.
    • 하위 객체로 만들 생성자 함수를 만든 후, 해당 생성자 함수의 프로토타입으로 상위 객체를 대입한다.
    • 이렇게 하면 상위 객체의 함수가 링크되어 그대로 이용할 수 있지만, 내부적으로 생성된 프로토타입 변수는 이용할 수 없다.
    • 예시
      function Person(name) {
        this.name = name;
      }
      
      Person.prototype.getName = function () {
        return this.name || '건열'
      }
      
      function Korean(name) {}
      Korean.prototype = new Person();
      
      const ryu = new Person('류건열');
      const kim = new Korean('김건열');
      console.log(ryu.getName()); // 류건열
      console.log(kim.getName()); // 건열
      
  2. 상속 흉내내기 2 - 부모 생성자 빌려쓰기
    • 부모 생성자를 빌려쓴다면 변수도 그대로 담기게 되어 위에서의 문제점을 해결할 수 있다.
    • 예시
      function Person(name) {
        this.name = name;
      }
      
      Person.prototype.getName = function () {
        return this.name || '건열'
      }
      
      function Korean(name) {
        Person.apply(this, arguments);
      }
      Korean.prototype = new Person();
      Korean.prototype.setName = function (name) {
        this.name = name;
      };
      
      const ryu = new Person('류건열');
      const kim = new Korean('김건열');
      console.log(ryu.getName()); // 류건열
      console.log(kim.getName()); // 김건열
      kim.setName('박건열');
      console.log(kim.getName()); // 박건열
      
  3. Object.create - 기존 객체 재활용
    • 에시
      const ryu = {
        name: '류건열',
        getName: function () {
          return this.name;
        },
      };
      
      const kim = Object.create(ryu);
      kim.name = '김건열';
      
      console.log(ryu.getName()); // 류건열
      console.log(kim.getName()); // 김건열
      console.log(lee.__proto__); // {}
      console.log(kim.__proto__); // { name: '류건열', getName: [Function: getName] }
      


이벤트 루프

JavaScript는 Single Thread로 동작한다.

실제로 위 그림처럼 JavaScript의 Call Stack은 하나만 존재한다.

그렇다면 브라우저에서 실행되는 스크립트는 어떻게 비동기적으로 불러오고 애니메이션을 실행할까? 어떤 원리로 애니메이션과 클릭 이벤트를 같이 처리할 수 있을까?

브라우저에 이벤트 루프라는 시스템이 있기 때문이다.

위 그림처럼 이벤트 루프는 자바스크립트 엔진에 포함되어 있지 않기 때문에 자바스크립트의 기능이 아니고 브라우저나 node.js에서 자체적으로 관리한다.

위 그림 우측 상단의 Web API는 브라우저에서 제공하는 API이다.

Click과 같은 웹 이벤트나 Timer 등은 실행시킬 경우 브라우저에 위임된다.

보통 Web API는 콜백함수를 넘기는데, 이 콜백함수는 비동기작업이 끝나면 Task Queue에 넣어져 순차적으로 꺼내 Call Stack에 push된다.

그래서 이런 과정들은 멀티 쓰레드로 동작한다. 자바스크립트 엔진이 싱글 쓰레드일 뿐 브라우저는 멀티 쓰레드로 동작하기에 이런 과정들이 가능해진다.


모듈

일반적으로 웹 사이트는 여러개의 자바스크립트로 이루어져 있다. 대부분의 스크립트 언어의 특징이지만, 자바스크립트는 파일들을 각각 별개의 프로그램으로 취급한다. 문제는 웹사이트가 점점 하는일이 많아짐에 따라 스크립트 파일도 크게 증가하게 되었다는 점이다.

예전 자바스크립트는 스크립트 파일간 통신을 위해 전역 스코프에 존재하는 변수와 함수를 사용해야 했다. 즉시 스코프를 활용하여 전역 스코프가 오염되는 것을 어느정도 막을 수는 있었지만, 스크립트 파일간 의존도를 확인하기 힘들고 실행 순서를 제어해야 한다는 한계점이 있었다.

이런 불편한 점들 때문에 노드들이 등장했는데, 노드를 사용하면 스크립트간 의존도를 확인할 수 있고, 실행 순서를 쉽게 제어할 수 있게 된다.

모듈과 컴포넌트의 비교

모듈은 설계 시점에 의미있는 요소이고, 컴포넌트는 런타임 시점에 의미있는 요소이다. 즉, 모듈은 우리가 의식적으로 나눠놓은 요소이고, 컴포넌트는 나눠놓은 요소에 포함되어 실행되는 요소이다.

모듈

그런데 자바스크립트의 모듈은 직접적으로 런타임에 실행되는데, 왜 이름이 모듈일까?

자바스크립트는 파일 하나가 프로그램이기 때문으로 추측된다.

설계시 용어가 혼동되는 경우가 많기 때문에 디렉토리 단위를 모듈 개념에 가깝게 사용하는 경우가 많다.

모듈은 로컬 파일에서 동작하지 않고 HTTP 또는 HTTPS 프로토콜을 통해서만 동작하기 때문에 서버를 실행시킬 필요가 있다.

모듈의 특징

  1. 항상 엄격 모드(use strict)로 실행된다.
    • 예를 들어, 일반 스크립트는 let이나 var를 생략하고 변수 선언이 가능해 전역 스코프에 저장되는 반면 모듈 스크립트는 엄격 모드로 실행되기 때문에 허용되지 않는다.
  2. 모듈 레벨 스코프가 있다.
    • 모듈은 최상위에 변수를 선언하더라도, 전역 스코프에 올라가지 않고 자체적인 모듈 레벨 스코프에 올라간다. 일반 스크립트는 최상위에 선언하면 전역 스코프에 선언되어 다른 스크립트에서도 참조가 가능하지만, 모듈 스크립트에서는 import하지 않는 한 서로 참조가 불가능하다.
  3. 단 한 번만 평가된다.
    • 여러번 import 되어도 실행은 단 한 번만 된다. 만약 내보내기를 하더라도 이미 평가된 것을 불러와서 사용하기만 할 뿐이다.
  4. 지연 실행된다.
    • 일반 스크립트는 body 태그에 넣을 경우 순서에 따라 DOM이 생성되기 전에 실행될 수 있다. 하지만 모듈 스크립트는 defer 옵션을 넣지 않아도 자동으로 지연 실행이 되어 모든 DOM이 만들어진 후에 실행된다.

그러나 요즘에는 Webpack 등을 이용하여 번들링한 스크립트를 불러오면 모듈 스크립트를 사용할 일이 별로 없다.


❗️ 느낀점

여태까지 공부하면서 얼핏 들어보거나 대충만 알고 있던 내용이 많았다.

2일차 강의를 수강하며 가장 크게 느낀점은 앞으로 모르거나 알아야할 것 같은 부분에 대한 학습을 진행할 때 나중에 편하게 다시 찾아보기 위함이나 기억에 더 잘 남을 수 있도록 블로그에 정리해야 겠다는 점이다.

특히 프로토타입 부분에서 두 객체를 생성할 때 따로 중복된 메소드가 생성되어 메모리가 낭비된다는 점이 흥미로웠다.

또 강사님께서 이벤트 루프에 대한 설명을 하실 때 이벤트 루프의 동작 과정에 대해 상세하게 설명해주셔서 이해하기 쉬웠다.

근데 또 적다보니 노션에 너무 많이 적어서 정리하는데 너무 힘듦..😢 요약하는 습관이 아직 안들여진 것 같다..

오늘도 고생했다👊