[DAY-3] JS 주요문법 (2)

박민우·2023년 6월 5일
0

✏️ TIL

목록 보기
3/6
post-thumbnail

오늘의 내용은 네트워크 기초, 컴퓨터 시간, 암호화, 함수형 프로그래밍, 객체지향, 이벤트 루프 등에 대한 내용이었다.
지금 당장 필요하진 않더라도, 프론트엔드 개발자로써 언젠가 한번쯤 만나게 될 내용이라 생각해, 꼼꼼하게 정리하려고 노력했다 ✏️


[1] - 네트워크 기초

📌 브라우저에 URL을 입력하면 생기는 일

  1. URL을 해석한다.

  2. DNS를 조회한다.

  3. 해당 IP가 존재하는 서버로 이동한다.

    네트워크 장비 라우터를 통해 이동한다.

    동적 라우팅을 통해 이동한다.

  4. ARP를 이용하여 MAC 주소 변환을 한다.

    네트워크 내에 ARP를 BroadCasting 하면 해당 IP 주소를 가지고 있는 기기가 MAC 주소를 반환한다.

  5. TCP 통신을 위해 Socket을 연다.

    • 네트워크를 통해 해당 기기로 패킷을 전달한다.
    • 3 way handshake로 연결을 요청한다.
    • 요청이 수락되면 기기는 패킷을 받아 처리한다.
  6. 데이터가 서버에 전달이 되면, 서버는 응답을 반환한다.

    • HTTP 프로토콜로 들어온 패킷을 읽고 처리한다.
  7. 브라우저가 렌더링한다.


📌 HTTP vs HTTPS

  • HTTP

    클라이언트와 서버 간의 데이터를 주고 받기 위한 통신 규약.

  • HTTPS

    HTTP와 기본 구조는 동일하나 SSL 또는 TLS를 프로토콜을 통해 보안성을 강화한 프로토콜

    HTTP는 암호화되지 않은 데이터를 전송하지만, HTTPS는 모든 데이터를 암호화된 형태로 전송한다.

    => 데이터를 주고 받는 과정에 '보안' 요소가 추가된다는 것이 가장 큰 차이점!


HTTP의 필요성

HTTP는 암호화가 전혀 되어 있지 않은 프로토콜로 Wireshark와 같은 패킷캡쳐 프로그램으로 패킷캡쳐를 해보면 정보가 그대로 노출되어 있다. 반면, HTTPS를 보안성을 강조하기 위해 패킷을 암호화하여 전송하게 된다. 그렇기 때문에 패킷캡쳐 프로그램으로 캡쳐를 해도 암호화된 내용만 보이게 된다.



[2] - 컴퓨터시간 원리

시간을 생각할 때, 꽤 많은 조건을 고려하여 시간을 표시해야 함.


📌 컴퓨터가 시간을 표현하는 방법

각 컴퓨터는 자체적으로 하드웨어인 시스템 클럭을 가지고 있다.

특정 시각을 기준으로 시스템 클럭의 틱을 세는 것만으로 시간을 계속 더해서, 구현할 수 있다.

=> 이를 시스템 시간이라 부른다.

=> 이를 값으로 표현한 것을 타임스탬프라고 부른다.

=> 이 중, 표준으로 많이 사용하는 것을 Unix Time 이라 부른다.


시스템 클럭의 원리

=> RTC(Real time Clock)이라는 모듈을 사용한다.


Unix Time의 원리

1970년 1월 1일 0시 0분 0초를 기준으로, 지난 초(second)를 나타낸다.


그래서, 컴퓨터는 현재 시간을 어떻게 알아낼까?

=> 시스템 시간을 NTP(네트워크 타임 프로토콜)을 통해 서버에서 받아오는 것

=> 결국, 인터넷이 없으면 현재 시간을 알 수 없는 것.


시간을 어떤 기준으로 사용해야 할까?

=> 글로벌 서비스를 운영한다면 시간이 매우 중요해진다.

=> 서비스에서 사용되는 시간을 용도에 맞춰서 기록할 필요가 있다.


JS에서 시간 사용법

  • 간단한 사용 => Date 객체
  • TimeZone 등 사용 => data-fns, luxon 사용


[3] - 암호화

평문을 암호문으로 변환하는 것

단방향 암호화

  • 해시 알고리즘을 이용해 평문을 복호화 할 수 없는 형태로 암호화

  • Rainbow table을 통해 원문을 알아낼 수도 있으니 Salt, Key strectching 등으로 조취를 취한다.


양방향 암호화

  • 대칭키 알고리즘 : 같은 키 이용
  • 비대칭키 알고리즘 : 공개키, 개인키 이용

브라우저는 암호를 어떻게 보관할까 ?

크롬이나 사파리, 1password는 암호를 보관하고 동기화해준다.

=> 구체적으로 알려진 바는 없다


JS에서 암호화를 하고 싶다면?

crypto-js 라이브러리 이용



[4] - 함수형 프로그래밍

📌 함수형 패러다임

  • 객체지향 추상화의 최소 단위가 객체인 것처럼 함수형은 함수가 최소 단위이다.

  • data의 불변성을 지향하기에 동작을 예측하기 쉽고 사이드 이펙트를 방지한다.

    => 사이드 이펙트를 방지한다는 것은 동시성 문제도 해결된다는 의미

  • 객체지향은 제어흐름의 간접적인 전환에 부과되는 규율

    vs 함수형은 변수 할당에 부과되는 규율


📌 패러다임 간 구현의 차이

Q."12345"의 각 자릿수를 모두 더해서 출력하는 프로그램

함수형 프로그래밍

const stringNumber = "12345";
console.log(
	stringNumber
		.split('')
		.map(x => parseInt(x))
        .reduce((x,y) => x + y, 0);
);

객체지향 프로그래밍, 절차지향 프로그래밍에서는 각각 접근하고 구현하는 방식이 다르다.


함수형 프로그래밍의 특징
  • 상태가 없기 때문에 사이드 이펙트가 없다.

  • 재사용성이 높고, 코드가 짧고 간결하다.


📌 선언형 프로그래밍

객체지향이나 함수형처럼 설계에 대한 패러다임이라기 보다는, 사고에 대한 패러다임에 가깝다.

=> 기존 명령형 프로그래밍은 문제를 어떻게 해결해야 하는지 컴퓨터에게 명령을 내린다면, 선언형 프로그래밍은 무엇을 해결해야 할지에 집중하고, 해결 방법은 컴퓨터에게 위임하는 방법


명령형

let a = [1,2,3,4,5];
for(let i=0;i<5;i+=1){
    if(a[i] %2 === 0){
        console.log(a[i]);
    }
}

변수를 선언하고, 데이터를 대입하고 루프를 돌면서 조건에 따라 출력한다 ~ 는 명령을 내림.


선언형

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

data 중 짝수만 걸러내는 것이 필요하고, 출력하는 것이 필요하다는 것을 분석해 컴퓨터에게 알려줌

=> 선언형을 위해 문제를 쪼개어 분석할 때, 함수형 프로그래밍이 빛을 본다.


사실, JS는 멀티 패러다임이 가능하다 => 굳이 객체지향과 함수형으로 나눌 필요 없이 둘 다 쓰자 !



[5] - 객체지향과 프로토타입

객체지향의 객체는 현실에 있는 것을 추상화한 것

=> 현실에 존재하는 것을 그대로 코드로 옮기는 것이 아닌 특징만 !


📌 객체지향에 대한 오해

  • 객체지향은 패러다임일 뿐 언어와는 관계가 없다.

    => JS, GO, C 언어로도 객체지향 프로그래밍을 할 수 있다.

    => JS는 프로로타입을 통해 객체 지향을 표현한다.

  • 절차지향보다 객체지향이 무조건 더 좋은 것은 아니다.

    => 간단한 프로그램 : 절차 지향이 적합

    ​ 복잡한 프로그램 : 객체 지향이 적합


📌 자바스크립트의 객체

클래스 기반 언어처럼 속성과 행위를 정의할 수 있다 => 객체 지향 프로그래밍 가능

const person = {
    name: "박민우",
    company: "google",
    move: function (destination){
        console.log(`${destination}으로 이동합니다.`);
    }
}

console.log(person.name);
console.log(person.company);
person.move("판교");

객체 생성 방법

  1. 객체 리터럴
  2. Object 생성자 함수
  3. 생성자 함수

자바스크립트의 객체만으로 객제 치향이 가능한데 왜 프로토타입이 필요할까 ?

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

const park = new Person("박민우", "KDT");
const kim = new Person("김민우", "KDT");
console.log(park);
console.log(kim);

이렇게 객체로 선언한다면 아래처럼 getNamesetName function이 객체 instance 마다 따로 선언이 되어 메모리가 낭비되게 된다.

Person{
    name: '박민우',
    company: 'KDT',
    getName: [Function],
    setName: [Function]
}

Person{
    name: '김민우',
    company: 'KDT',
    getName: [Function],
    setName: [Function]
}

이러한 문제를 프로토타입을 통해 해결할 수 있음.

=> 프로토타입을 통해 상위 객체를 참조할 수 있고, 객체를 이용해 새로운 객체를 추가적으로 만들어갈 수 있다.


[6] 이벤트 루프

📌 이벤트 루프

JS Engine에 Call Stack은 하나만 존재하기 때문에 자바스크립트는 Single Thread로 동작한다.

그러면 브라우저에서 실행되는 스크립트는 어떻게 비동기적으로 데이터를 불러오고, 애니메이션을 실행시킬까 ?

=> 브라우저의 이벤트 루프라는 시스템이 있기 때문.

image-20230602232918499

  • 이벤트 루프는 JS Engine에 포함 되어있지 않고, 브라우저나 nodeJS에서 자체적으로 관리

  • Web APIs : 브라우저에서 제공하는 API

    => click과 같은 Dom event, 네트워크 호출, timer 등은 실행 시 브라우저에게 위임된다.

    => 이런 Web API는 콜백함수를 넘기게 되는데, 이 콜백함수는 비동기 작업이 끝난 후 Task Queue에 넣어져, 순차적으로 꺼내 Call Stack에 Push가 된다.

=> 그래서 이러한 과정들은 결국 멀티 스레드로 동작한다.

=> JS 엔진이 싱글 스레드일 뿐, 브라우저는 멀티 스레드로 동작하기 때문에 이런 과정이 가능하다.


이벤트 루프의 동작 과정

이벤트 루프의 역할 : call stack이 비어있다면 task queue에서 첫번째 task를 call stack에 넣고, 이를 실행한다.

  1. 스크립트가 실행되면 Global Scope에서 실행

  2. 코드가 순차적으로 실행

  3. Call stack에 쌓임과 동시에 Web API 실행 (콜백 함수)

    => 함수가 종료되면 Call stack에서 나가고, 다음 함수가 쌓인다.

  4. Web API에서 콜백 함수를 Task Queue에 밀어넣고,

    Call stack이 비어있으면 Task Queue에서 나와 해당 함수들이 쌓인다. (이를 Tick 이라고 한다)

  5. 다시 Call stack이 비면 다음 콜백 함수가 Call stack에 쌓이게 된다.

Web API : 브라우저에서 제공하는 API / 콜백 함수를 Queue에 넣어주는 역할
Task Queue : 비동기로 실행된 콜백 함수가 보관되는 영역


Microtask Queue, Animation frames 이란 ?


[7] - 모듈

일반적으로 웹 사이트는 여러개의 JS로 이루어져있다.

=> JS는 파일들을 각각 별개의 프로그램으로 취급한다

=> 예전 JS는 스크립트 파일 간 통신을 위해 전역 스코프에 존재하는 변수와 함수를 사용했음

=> 스크립트 파일 간 의존도를 확인하기 힘들도 실행순서를 제어해야 한다는 한계점이 있었음.

=> 모듈을 사용하면 의존도를 파악할 수 있고, 실행순서를 쉽게 제어 가능


모듈 vs 컴포넌트의 차이

모듈은 설계 시점에 의미있는 요소이고, 컴포넌트는 런타임 시점에 의미있는 요소이다.

=> 모듈은 우리가 의식적으로 나눠놓은 요소이고, 컴포넌트는 나눠놓은 요소에 포함되어 실제로 실행되는 요소를 말한다.

=> 하지만 JS에서의 모듈은 직접 런타임에 실행이 된다 ?

=> JS에서는 파일 하나가 프로그램이기 때문에 모듈이라 지었을 것이라 추측


📌 모듈 기초 사용 방법

JS가 지원하는 모듈은 로컬 파일에서 동작하지 않고 HTTP혹은 HTTPS 프로토콜을 통해서만 동작하기 때문에 서버를 실행시켜야 함


hello.js

export function hello(name){
    alert(`Hello, ${name}!`);
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Module Example</title>
</head>
    
<body>
    <script type="module">
    	import { hello } from './hello.js';
        
        hello('John');
    </script>
</body>
</html>
  • script 속성으로 type = "module"이므로 이는 모듈로 동작한다는 뜻

📌 모듈의 특징

  • 항상 use strict로 실행된다.

    => 일반 script는 let이나 var를 생략하고 변수를 선언하면 global scope에 저장됨

    => 엄격 모드에서는 이를 허용하지 않음 (Referrence Error)

  • 모듈은 자체적인 모듈 레벨 scope가 있다.

    => 모듈은 최상위에 변수를 선언하더라도, 전역 scope에 올라가지 않고 자체적인 module level scope에 올라간다.

    => module script에서는 import 하지 않는 한, 서로 참조가 불가능하다.

  • 단 한번만 평가된다

    => 한 파일에서 2번 이상 import 되더라도, 실행은 한번만 된다.

  • 지연 실행된다

    일반 script는 body 태그에 넣을 경우 순서에 따라 dom이 생성되기 전에 실행될 수 있지만

    module script는 defer 옵션을 넣지 않아도 자동으로 모든 dom이 만들어진 후 실행이 된다.


[8] - 유니코드

웹 브라우저는 다양한 문자(영어, 한국어, 일본어 등)을 표시한다.


문자가 브라우저에 표시되는 과정

  • 값으로 이루어진 문자글꼴이 만나 렌더링 엔진을 통해 그려진다.

CCS (Coded Character Set)

  • 문자들을 Code Point에 대응시켜 만든 코드화된 문자들의 집합

  • Code point는 정의해놓은 정수값이고, 각 문자들의 식별자가 된다.

  • ASCII 코드도 CSS 중 하나


CES(character Encoding Scheme)

  • CCS를 8bit 집합에 대응시킨 것

  • 문자를 표현하는 기본 단위가 8bit이기 때문

  • CCS와 CES는 1:1로 대응된다.

  • 이것이 흔히 말하는 인코딩에 해당한다.

    인코딩 - Character를 시스템이 인식할 수 있는 값으로 변환하는 것

  • 이 변환 방법은 인코딩 방법마다 다르기 때문에 서로 호환이 안될 수 있음


TES

  • 인코딩한 문자가 특정 프로토콜을 타고 전송이 가능하도록 변환하는 것

    EX) url에서 공백은 사용 불가능하기 때문에 별도로 url 인코딩을 하여 전송해야 한다.


유니코드

  • 전세계 문자를 컴퓨터에서 다룰 수 있도록 하는 표준 시스템

[9] - 정규표현식

정규 표현식은 "특정 패턴의 문자열" 을 찾기 위한 표현 방식

  • 문자 검색
  • 문자 대체
  • 문자 추출

을 할 수 있다.

성능은 매우 느리지만, 매우 편하다 !


/ regexr / i

  • / => 시작, 종료기호
  • regexr => 패턴
  • i => 플래그

ex) 정규표현식으로 전화번호 찾기

\d{3} => 세 자리 아무 숫자

\d{3,4} => 세,네 자리 아무 숫자

이 패턴들을 조합해보면

\d{3}-\d{3,4}-\d{4}


ex) 이메일에서 중간 문자열만 뽑아내기

alsd2013@naver.com

.+ => 한 개 이상의 문자열

(...) => 캡처

이를 조합해서

.+@(.+)\..+


📌 JS에서 정규표현식 사용

생성 방법
  • JS는 regExp 객체로 정규표현식 기능을 제공한다.

  • 생성자 함수 방식으로 생성할 수 있다.

    const regExp1 = new RegExp("^\d+");

  • Array, Object 처럼 Literal로 생성이 가능하다.

    const regExp1 = /6\d+/;

객체 함수

regExp.함수이름 으로 사용 가능하다.

  • test : 입력 받은 문자열에 찾는 패턴이 있는지 찾은 후 있다면 true를 반환

  • exec : 입력 받은 문자열에 찾는 패턴이 있는지 찾은 후 일치한 패턴 정보를 반환하고 없으면 null을 반환한다. 문자 추출이 가능하다.

  • match : 이는 String 객체의 함수로 정규표현식 객체를 파라미터로 받아 패턴이 있는지 확인 후 일치한 패턴 정보를 반환한다.

  • replace : String 객체의 함수로, 패턴이 있는지 찾은 후 일치한 패턴 정보를 원하는 문자열로 바꿀 수 있다.

  • search : String 객체에서 패턴을 찾을 후, 일치한 패턴 정보의 위치 반환한다.
  • capture : () 로 감싸며 사용하고, match 반환값의 1번 인덱스부터 순차적으로 캡처 결과가 들어간다.

Run-length encoding 예제

  • "AAAAAABBBDFFFFFFFKK" 문자열을 어떻게 압축할 것인가?

    => "6A3B1D7F2K" 로 압축할 수 있다.

const raw = "AAAAAABBBDFFFFFFFKK";
const compressed = "6A3B1D7F2K"; // 정답 

const regExp = /(.)\1*/g;
const result = raw
	.match(regExp)
	.reduce((a,b) => a + `${b.length}${b.slice(0,1)}`,"");

console.log(reuslt);
console.log(result === compressed);

선택과제

개미 수열을 정규표현식을 이용하여 풀어보자

개미수열이란

  • 5를 입력받으면 111221이 나와야 한다.

[10] - 쿠키와 세션, 웹 스토리지

HTTP 통신

  • HTTP request는 기본적으로 stateless
  • 따라서 서버는 어떤 브라우저에서 요청이 온 것인지 알 수 없다
  • 이때 헤더에 쿠키를 담으면 서버가 쿠키를 읽어 어디서 온 것인지 알 수 있다.

  • 클라이언트에서 저장, 관리하는 데이터

    => 브라우저를 닫아도 데이터 유지

  • 서버에서 Set-Cookie를 응답 헤더로 내려주면 클라이언트는 이를 저장

  • 각 상태에 수명을 정할 수도 있다.

  • 매번 서버에 전송되기 때문에 크기가 클 경우 서버에 부담이 갈 수 있다.


  • Set-Cookie: 키=값; 옵션 의 형태

  • 응답 헤더에 담으면 브라우저가 알아서 저장한다


쿠키의 취약점

  • XSS(Cross-Site-Script) 공격을 당할 수 있다.

    XSS란?

    악성 스크립트를 삽입하여 의도하지 않은 명령을 실행시키거나 쿠키나 세션 등을 탈취하는 것

  • 쿠키를 암호화하지 않고 보내면 중간에 탈취 당할 가능성이 높다

    => HTTPS 를 이용하면 해결 가능


사실 클라이언트가 아무리 쿠키를 보내도 서버는 그 쿠키 주인이 누구인지 모른다.

=> 서버가 사용자를 구분하도록 하려면 ?

=> 세션을 이용


📌 Session

  • 서버 자체적으로 세션을 기록하기 관리해, Session id를 식별자로 사용자를 구분한다.

    클라이언트는 이 Session id를 쿠키 형태로 저장한다.

  • 하지만 요즘에는 Session의 문제가 있어서 인증 용도로 사용하지 않는다 !

    => 이제 서버와 클라이언트간 인증은 별도 토큰을 사용하고, 쿠키는 클라이언트 자체적인 지속적인 데이터 관리 용도로 사용


📌 웹 스토리지

  • 로컬 데이터를 관리하는 새로운 방법

  • 쿠키가 하기 힘든 것들을 지원해준다

  • 로컬 스토리지, 세션 스토리지가 존재하고, 이들은 window 객체의 프로퍼티로서 존재하며, 같은 Storage 객체를 상속하기 때문에 동일한 메서드들을 가진다 .

  • 쿠키와 달리 서버에 전송되지 않으므로 서버에 부담이 가지 않는다(명시적으로만 전송 가능)


로컬 스토리지

  • 여기에 데이터를 저장하면 반영구적으로 데이터가 저장됨

    => 유효기간이 필요없는 데이터를 담을 때 유용

    ex) 자동로그인 등

    => 브라우저를 종료해도 계속해서 데이터가 남는다.

  • 도메인 별로 생성되며, 다른 도메인의 로컬 스토리지에는 접근 불가능

    => 서로 다른 브라우저 탭이라도 동일한 도메인이라면 동일한 로컬 스토리지 사용


세션 스토리지

  • 새 창, 새 탭을 생성할 때마다 개별적으로 데이터를 저장, 관리

웹 스토리지 사용 예제

localStorage.setItem('name', '박민우');
console.log(localStorage.getItem('name'));

// 데이터 지우기
localStorage.removeItem('name');

// 데이터 전부 지우기
localStorage.clear

sessionStorage.setItem('name', '박민우');
console.log(sessionStorage.getItem('name'));

// 데이터 지우기
sessionStorage.removeItem('name');

// 데이터 전부 지우기
sessionStorage.clear

📌 Indexed DB

IndexedDB는 파일이나 블롭 등 많은 양의 구조화된 데이터를 클라이언트에 저장하기 위한 로우 레벨 API 이다.

  1. 많은 양의 구조화된 데이터를 클라이언트에 저장할 수 있다.

    • 브라우저마다 편차는 있지만, 보통 HDD 용량의 50% 이다.
      (Local Storage의 용량은 겨우 10MB이다)
  2. Javascript 기반의 객체지향 데이터베이스

    => 즉, Javascript가 인식할 수 있는 자료형과 객체를 저장할 수 있다!
    (Local Storage는 String 형태만 저장할 수 있다)

  3. transaction을 사용하며 Key-Value 데이터베이스이다.

  4. IndexedDB는 비동기 API이다.


IndexedDB 사용 패턴
  1. 데이터베이스를 열고
  2. 객체 저장소(Object store)를 생성한 뒤
  3. 트랜잭션(Transaction)을 시작하고 데이터베이스 작업(데이터 읽기/추가 등)을 요청한다.
  4. DOM EventListner를 사용하여 요청이 완료될때가지 기다리고 결과를 확인한다.

➕ 브라우저 정보 저장 방법

쿠키, 세션, 웹 스토리지, Indexed DB 외에도 브라우저에 정보를 저장할 수 있는 방법은 많다.

각 상황에 맞는 저장 방법을 선택해 사용해야 한다.

웹 스토리지: 무엇을 써야할까?



참고

HTTP vs HTTPS

이벤트 루프

이벤트 루프란

모듈에 대한 이해와 사용법

모듈이란?

정규표현식 기초

쿠키, 웹 스토리지

IndexedDB에 대해 알아보자

profile
꾸준히, 깊게

0개의 댓글