호이스팅 (Hoisting)

호이스팅이란 함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것이다.

오해가 있을 수 있는 부분인데, 실제로 코드가 끌어올려지는 것은 아니며, javascript Parser 내부적으로 컴파일 단계에서 끌어올려 처리하는 것이다.

catName('Chloe');

function catName(name) {
    console.log("My cat's name is " + name);
}

위 코드에서 함수를 작성하기 전에 함수를 호출하였지만, 코드는 정상적으로 작동한다.

var 변수 선언함수선언문에서만 호이스팅이 일어난다.
var foo2 = function(){...} 형식의 함수표현식let/const 변수 선언에서는 호이스팅이 발생하지 않는다.

var 변수/함수의 초기화(할당)가 아닌 선언만 끌어올린다. 변수를 선언한 뒤에 나중에 초기화시켜서 사용한다면, 그 값은 아래 예시와 같이 undefined로 지정된다.

var x = 1; // Initialize x
var y; // Declare y
console.log(x + ' ' + y); // '1 undefined'
y = 2; // Initialize y

코드의 가독성과 유지보수를 위해 호이스팅이 일어나지 않게 해야하며, let/const 를 사용함으로써 이 문제를 방지할 수 있다.

ES6를 모든 브라우저가 지원하는 것이 아니므로, ES5로 babel 등을 통해 트랜스컴파일을 진행해야 하고 이것이 var의 동작에 대해 FE 개발자가 이해하고 있어야 하는 이유이다.

Reference

'Language > JavaScript' 카테고리의 다른 글

자바스크립트 Primitive(원시값)  (0) 2020.06.13
자바스크립트 클로저  (0) 2020.06.12
CORS  (0) 2020.05.04
SPA란  (0) 2020.01.07

Primitive

Javascript에서 원시값(primitive, 원시 자료형)이란 객체도 아니고 메서드도 아닌 data이다.
총 7개의 원시 자료형이 존재한다.

  • string
  • number
  • bigint
  • boolean
  • null
  • undefined
  • symbol (ES16에서 추가)

모든 primitive는 불변이다. primitive 자체와 primitive을 할당한 변수를 혼동하지 않아야 한다. 변수는 새로운 값을 다시 할당할 수 있지만, 이미 생성한 primitive는 객체, 배열, 함수와 달리 변형이 불가하다. 여기서 객체, 배열, 함수를 원시값과 구별하여 참조 타입(reference type) 이라고 부른다.

var numberPrimitive = 10;
var booleanPrimitive = false;
var stringPrimitivie = 'string boy';

위 코드에서 예를 들어 설명을 하자면, 대입되는 오른쪽 값이 primitive로 보면 되고, 실제 작동할 때는 변수를 이용하여 작업을 한다. 원시값이 변하지 않는 이유는, 원시값에 직접 작업하는 것이 아니라, 원본을 건드리지 않고 복사본을 가져와 작업을 하는 것이기 때문.

  • 각각의 값은 모두 스택에 저장된다
  • 변수 자체가 하나의 값을 가진다.
  • 인자가 전달될 때 call by value의 형태로 넘어간다.
  • primitive type의 값은 immutable하다.

null과 undefined를 제외하고, 모든 primitive는 원시값을 래핑한 객체를 가진다.

  • 문자열 원시값을 위한 String 객체
  • 숫자 원시값을 위한 Number 객체
  • 빅인트 원시값을 위한 BigInt 객체
  • 불리언 원시값을 위한 Boolean 객체
  • 심볼 원시값을 위한 Symbol 객체

Reference

'Language > JavaScript' 카테고리의 다른 글

호이스팅 (Hoisting)  (0) 2020.06.14
자바스크립트 클로저  (0) 2020.06.12
CORS  (0) 2020.05.04
SPA란  (0) 2020.01.07
  1. 예증법 : 특정한 사례들을 나열한 뒤 그 안에서 일반적인 규칙을 찾는다.

  2. 패턴 매칭 : 풀어야 할 알고리즘과 비슷한 문제를 생각해내고 비슷한 문제의 풀이법을 수정하여 풀어야 할 알고리즘을 만들어낸다.

  3. 단순화와 일반화 : 문제를 단순화하여 푼 뒤, 알고리즘이 구해지면 일반화

  4. 초기 사례로부터의 확장 : n=1, n=2, n=3,... 식으로 확장하여 규칙을 찾아낸다. 보통 재귀 알고리즘으로 구현된다.

  5. 자료구조 브레인스토밍 : 자료구조들을 차례차례 적용해보고 해결되는지 본다.

'코딩테스트' 카테고리의 다른 글

알고리즘 풀이 블로그  (0) 2020.07.15
백트래킹, N Queen  (0) 2020.02.17
DFS, BFS  (0) 2020.01.23
DP  (0) 2020.01.17
코테 에러 분석  (0) 2020.01.07

클로저(Closure)

클로저는 함수의 실행이 끝난 뒤에도 함수에 선언된 변수의 값을 접근할 수 있는 자바스크립트의 성질이다. 바로 예시로 들어가보자.

function addCounter() {
    var counter = 0;

    return function () {
        return counter++;
    };
}

addCounter();
console.log(counter);

위 코드는 오류가 나는 코드이다. addCounter() 함수의 실행이 끝난 시점에서 counter라는 변수는 더이상 접근을 할 수 없는 상태이다. 함수 안에 선언한 변수는 함수 안에서만 유효 범위를 갖기 때문이다.

function addCounter() {
    var counter = 0;

    return function () {
        return counter++;
    };
}

var add = addCounter();
add();
add();
add();

아까와는 달리 이 코드는 오류 없이 실행된다. addCounter() 함수가 반환한 함수를 add라는 변수에 담아놓았기 때문에 add 자체가 함수처럼 동작하는 것이다.

addCounter()의 반환 함수는 자신이 생성된 렉시컬 스코프에서 벗어나 global에서 add라는 이름으로 호출이 되었다. 이런 add 와 같은 함수를 클로저라고 부른다.

addCounter() 의 렉시컬 스코프에서 생성된 instance는 addCounter(); 수행이 끝난 후에 Garbage Collector가 회수해야 하는데, 사실은 그렇게 작동하지 않는다. 위에서 설명한 것과 같이, addCounter()의 반환 함수는 렉시컬 환경인 addCounter()의 렉시컬 환경을 계속 참조하고 있고, global에서 add가 해당 함수를 계속 참조하고 있기 때문이다. 이 때문에 클로저를 남용하게 되면 메모리 이슈가 생기게 된다.

클로저를 응용하여 자바스크립트에 없는 private 변수를 구현할 수 있다.

function counter() {
    var _count = 0;

    return function () {
        _count += 1;

        return _count;
    };
}
var counterFirst = counter();
console.log(counterFirst());
console.log(counterFirst());

위와 같이 구현하면, _count 변수는 외부에서 접근할 수 없는 방법이 없다. counter() 함수 내에서만 접근할 수 있는 private 변수가 구현된 것이다.

Reference

'Language > JavaScript' 카테고리의 다른 글

호이스팅 (Hoisting)  (0) 2020.06.14
자바스크립트 Primitive(원시값)  (0) 2020.06.13
CORS  (0) 2020.05.04
SPA란  (0) 2020.01.07

GIL

  • GIL은 python의 메모리 관리와 깊은 연관이 있다. 따라서 python의 메모리 관리에 대해서 언급하고 넘어가고자 한다.

python의 메모리 관리

파이썬은 C, C++가 프로그래머가 직접 메모리를 관리하는 것과는 달리, 레퍼런스 카운트(Reference Counts)와 가비지 콜렉션(Automatic Garbage Collection)에 의해 관리된다.

레퍼런스 카운트(Reference Counts)

파이썬은 내부적으로 malloc()과 free()를 많이 사용하기 때문에 memory leak의 위험이 있다. 이러한 이유로 파이썬은 메모리 관리를 위해 레퍼런스 카운트를 사용한다.

레퍼런스 카운트

  • 객체에 카운트를 포함
  • 카운트는 객체가 참조될 때 증가
  • 참조가 삭제될 때 감소
  • 카운터가 0이 되면 메모리 할당 삭제

하지만 레퍼런스 카운트만으로 메모리를 관리했을 때에 약점이 있는데, 그것은 순환 참조이다.

순환 참조란 컨테이너 객체가 자기 자신을 참조하는 것이다. 자기 자신을 참조할 때 레퍼런스 카운트가 0에 도달할 수 없고 할당된 메모리를 삭제할 수 없어 memory leak이 발생한다.
파이썬은 이러한 문제를 가비지 콜렉션을 이용하여 해결한다.

가비지 콜렉션(Automatic Garbage Collection)

파이썬의 gc 모듈을 통해 가비지 콜렉터를 직접 제어할 수 있다. 파이썬에서는 Cyclic Garbage Collection을 지원하고, 이것은 참조 주기를 감지하여 메모리 누수를 예방한다.

  • 가비지 컬렉션의 기준

가비지 컬렉터는 generationthreshold 로 가비지 컬렉션 주기와 객체를 관리한다.
0세대, 1세대, 2세대로 총 3개의 영역으로 구분되며, 0세대에 가까울 수록 최근 생성된 객체, 2세대에 가까울수록 오래된 객체이다. generational hypothesis 에 따라 가비지 컬렉터는 0세대일수록 자주 가비지 컬렉션을 하도록 설계되어 있다.

  • 순환 참조 감지 방법

순환참조는 컨테이너 객체(tuple, list, set, dict, class) 에서만 발생할 수 있다. 순환참조 해결을 위해 모든 컨테이너 객체를 추적한다. 추가적인 메모리 할당을 하지 않기 위해 객체 내부 link field에 double linked list를 사용될 것이다. 컨테이너 객체가 생성될 때 컨테이너 객체 집합에 추가되고, 제거될 때 집합에서 삭제된다.

1. 객체 gc_refs 필드를 레퍼런스 카운트와 같게 설정
2. 각 객체에서 참조하고 있는 다른 컨테이너 객체를 찾고, 참조되는 컨테이너의 gc_refs를 감소시킨다.
3. gc_refs 가 0이면 컨테이너 집합 내부에서 자기들끼리 참조하고 있다는 것이므로 메모리에서 해제한다.

다시, GIL

  • GIL은 한번에 하나의 스레드만 수행할 수 있도록 인터프리터에 lock을 거는 기능이다.

  • 파이썬 객체는 가비지 컬렉션 기능을 위해, 레퍼런스 카운트를 가지고 있는데, 위에서 설명했듯이 해당 객체를 참조할 때마다 해당 값을 증가하고, 참조가 삭제될 때 감소해야 한다.

  • 멀티 스레드를 실행하게 되면, 각 thread가 공유하는 객체들에 대해 lock을 거는 경우(mutex), reference count를 변경하는 것에 있어 deadlock의 위험이 존재하기 때문에, 인터프리터 레벨에서 한 시점에 실행하는 스레드는 1개로 제한한 것이다.

  • 따라서 멀티 CPU 환경일지라도, 파이썬 thread는 1개만 실행된다.

  • 이를 해결하기 위해서 multiprocessing 라이브러리를 사용하면 개별 프로세스가 생성되고, 프로세스 별로 인터프리터 lock이 걸리기 때문에 동시에 실행이 가능하다.

  • 병렬처리에 관해서 굳이 thread가 아니더라도 multiprocessing이나 asyncio 등 많은 선택지가 있으며, 아직까지 단일 thread에서 성능을 저하시키지 않고 GIL을 개선할 수 있는 방안이 없기 때문에 GIL은 계속 유지되어 오고 있다.

Reference

HTTP 프로토콜

HTTP 프로토콜은 stateless 프로토콜이다. stateless란 다시 말해, 각각의 데이터 요청이 독립적으로 관리가 되는 것이고, 세션 등을 서버가 따로 관리하지 않는 것을 의미한다. 연결을 끊는 순간 클라이언트와 서버의 통신이 끊기며, 상태 정보를 유지하지 않는다.

  • 장점 : 불특정 다수를 대상으로 하는 서비스에 적합
  • 단점 : client가 로그인을 하더라도 로그 정보를 유지할 수 없다. 따라서 서버는 세션 정보를 cookie를 이용하여 관리한다.

HTTP 프로토콜은 TCP/IP 통신 위에서 동작하며 80번 포트를 사용한다.

How HTTP works

HTTP 프로토콜은 Request를 보내고 Response를 받는 식으로 동작한다. 즉 Client-Server 형식이다.

HTTP를 통해 전달되는 자료는 http:// 로 시작하는 URL로 조회가 가능하다.

HTTP 요청 메소드

  • GET: URL가 가진 정보를 조회를 요청

  • POST: 클라이언트에서 서버로 entity를 제출함. 때에 따라서 create, update, delete도 가능.

  • PUT: 내용 갱신. 전체 자원을 업데이트 할 때 사용한다.

  • DELETE: 리소스를 삭제

  • PATCH: 리소스의 부분을 수정하는 데 사용.

  • HEAD: 헤더 정보만 요청. response body를 반환하지 않음. 자원의 존재 유무만 확인할 때 사용

  • OPTIONS: 서버 옵션을 확인하기 위한 요청. CORS에서 사용

HTTP 상태 코드

  • 2XX : 성공
    • 200 : 오류없이 전송 성공
  • 3XX : 리다이렉션
    • 304 : 클라이언트의 캐시에 문서가 저장되었고, 선택적인 요청에 의해 수행됨
  • 4XX : 클라이언트 에러
    • 400 : 요청 실패. 문법상 오류가 있어 서버가 요청을 이해하지 못함
    • 401 : 권한 없음. 인증이 필요함.
    • 403 : 금지 (접근 거부 or SSL 등)
    • 404 : 문서를 찾을 수 없음. 서버가 요청한 리소스를 찾지 못함.
    • 405 : 메서드 허용 안됨
  • 5XX : 서버 에러
    • 500 : 서버 내부 오류. 서버가 요청을 수행할 수 없음.
    • 503 : 외부 서비스가 멈췄거나, 이용할 수 없는 서비스 (일시적)

HTTP 요청 메세지 형식

Request Header + Empty Line + Request Body

  • Header

    • 요청 메소드 + 요청 URI + HTTP Protocol 버전
    • GET /background.png HTTP/1.0
    • Header 정보 (날짜, 웹서버 이름 및 버전, 콘텐츠 타입 및 길이, 캐시 제어 방식, keep-alive 설정 등)
      • keep-alive란 지정된 시간동안 연결을 끊지 않고 요청을 계속해서 보내는 방식. TCP는 3 way-hanshake 방식으로 연결을 확인하는데, 매 데이터 요청마다 연결을 맺고 끊으면 비효율적이기 때문에 필요한 방식
  • Empty Line

    • 요청에 대한 모든 meta-content가 전송되었음을 알림
  • Body

    • POST와 PUT만 존재하는 부분
    • 요청과 관련된 내용
      • POST는 이 Body 안에 entity를 넘기고, GET은 url로 요청하는 정보를 넘긴다

HTTP 응답 메세지 형식

Response Header + Empty Line + Response Body

  • Header

    • HTTP Protocol 버전 + 응답 상태코드 + 응답 메세지
    • HTTP/1.1 404 Not Found.
  • Empty Line

    • 요청에 대한 모든 meta-content가 전송되었음을 알림
  • Body

    • 실제 응답 리소스 데이터

'Web' 카테고리의 다른 글

쿠키, 로컬 스토리지, 세션 스토리지  (0) 2020.06.17
Webpack  (0) 2020.02.22

+ Recent posts