JavaScript 가 가진 특성에 관하여

🪐 C:on·2022년 1월 18일
0

자바스크립트

목록 보기
1/4
post-thumbnail

모질라 자바스크립트 입문자용

문법이나 메서드에 관한 내용보다, 자바스크립트라는 언어가 가지는 특성을 중심으로 정리


🔎자바스크립트의 이해

자바스크립트는 가벼운 객체 지향 인터프리터 언어이다.

객체지향 인터프리터 언어란 기계어번역을 위한 컴파일 작업 없이 소스코드를 한줄한줄 읽어가면서 프로그램을 실행시키는 시점에 기계어로 번역하는 언어를 말한다. 그렇기에 컴파일 시간이 필요없지만 컴파일된 프로그램보다는 느리게 동작할 수 있다.

또한, 상속이 가능한 프로토타입 언어이다.



🔎객체

자바스크립트에서는 배열, 함수, API 등 대부분의 것들이 객체이다.
따라서 객체 기반의 자바스크립트 본질을 이해하는 것은 매우 중요하다.

객체를 이루는 것은 데이터와 함수인데 데이터는 객체의 프로퍼티, 함수는 메소드라고 부른다.


JSON과 객체의 차이

JSON은 자바스크립트 객체 리터럴 문법을 따르는 문자열이다.

단, 메서드는 담을 수 없다.

프로퍼티의 이름을 작성할 때는 무조건 큰 따옴표로 작성해야 하며 콤마나 콜론을 잘못배치하면 JSON파일이 작동하지 않으므로 주의해야 한다.

JSON을 활용하기 위해 다음 유용한 두가지 API가 있다.

  • parse() : JSON문자열을 매개변수로 수용하여 자바스크립트의 객체로 변환해준다.
  • stringify() : 객체를 매개변수로 수용하고 JSON문자열 형태로 변환한다.


🔎비동기 자바스크립트

우리는 가끔 모니터의 빙글빙글 돌아가는 스피너를 통해 로딩중임을 확인한다.
이것은 여러 프로세서 코어를 사용할 수 있는 현 시대의 컴퓨터 기술을 잘 활용하지 못한 문제이다.

자바스크립트는 싱글스레드이기때문에 코어가 여러개있더라도 메인스레드에서만 작업을 실행할 수 있다. 하나의 스레드는 하나의 스택을 가지며 이 콜스택에는 차례대로 실행할 함수들이 쌓인다.

nodeJS는 멀티쓰레드이지만 JS를 동작시키는 것은 단 하나의 쓰레드이다. 그래서 노드를 싱글스레드라고 얘기하는 사람들도 있다. 그렇다면 비동기는 어디서 처리되는 걸까?

노드JS 내부적으로 여러가지 모듈들이있다. 그 중 V8엔진으로 자바스크립트를 동작시키고 Libuv라는 라이브러리를 통해 file system, Network, streaming등의 API를 논블로킹I/O로 동작시킨다.

블로킹이란 어떤 처리때문에 앱이 프로세서 대한 제어권을 반환하지 않는 현상이다.

nodeJS가 읽는 자바스크립트 코드는 모두 하나의 싱글스레드(V8)에서 돌아간다.
하지만 I/O작업을 하는 노드의 내부 모듈은 C로 만들어진 Libuv라는 라이브러리를 통해 논블로킹으로 동작한다.
따라서 CPU연산이 많은 작업보다 I/O작업에서는 nodeJS가 더 유용하게 사용될 수 있다.


자바스크립트 비동기 동작 흐름

console.log('first')

setTimeout(function cb() {
    console.log('second')
}, 1000);

console.log('third')

위 코드를 실행하면 다음과 같은 순서로 런타임이 동작한다.

  1. 콜스택에 console.log('first') 를 추가한다.
  2. 콘솔에 first를 출력한뒤 콜스택에서 제거한다.
  3. 콜스택에 setTimeout() 을 추가한다.
  4. 백그라운드는 웹API의 timer를 호출하고 콜스택에서 제거한다. 요청한 시간이 지나면 콜백함수 cb를 테스크큐에 추가한다.
    a. 그 사이에 자바스크립트는 console.log('third') 를 콜스택에 추가한다.
    b. 콘솔에 third를 출력한 뒤 콜스택에서 제거된다.
  5. 이벤트루프는 상시로 콜스택의 상태를 확인하는데 콜스택이 비워지는 순간 테스크큐에 있는 cb를 콜스택에 추가한다.
  6. cb 함수가 실행되고 내부에 있는 console.log('second')가 콜스택에 추가된다.
  7. 스택의 후입선출 특성에 따라 console.log('second') 가 먼저 실행 후 제거되고 cb가 마지막으로 콜스택에서 제거되어 모든 코드의 동작이 마무리된다.

Promise란

프로미스는 자바스크립트의 최신 비동기 코드이다.

프로미스는 작업의 완료 또는 실패를 나타내주어 다음 이점을 갖는다.

  • 콜백지옥에서 자유롭다.

    • 콜백이 반복되면 코드가 에너르기파를 맞고 아파한다.
    • 프로미스는 then을 사용해 다음 작업을 입력함으로써 이런 들여쓰기 반복을 없애준다.
  • catch를 사용해서 각 콜백에서 개별적으로 처리하지 않고 블록 끝의 단일 블록에서 에러를 처리할 수 있다.

  • then..catch를 사용하면 무슨 일이 일어나고 있는지 훨씬 보기가 쉬워진다.

  • all을 사용하면 경쟁관계의 비동기의 완료순서를 신경쓰지 않고 코드를 작성하기가 수월해진다.

    • 가령 a,b라는 비동기 코드가 있고 누가 먼저 완료될 지 알 수 없는 상황에서 두 코드가 수행된 후 다음작업을 진행해야한다면 all을 사용하여 효율적으로 코드를 작성할 수 있다.

      Promise.all([a, b]).then(()=>{
      *console*.log("done!");
      }); 

프로미스는 생성될 때 pending 상태를 가진다.
이후 약속을 반환할 때 성공했을 경우에는 fullfilled, 실패했을 경우 rejected 상태가 된다.


Promise 만들기

프로미스 생성자를 사용해서 직접 프로미스를 만들 수 있다.
promise기반이 아닌 구식 비동기 API를 프로미스로 사용할 때 활용한다.

function timeoutPromise(message) {
  return new Promise((resolve, reject) => {
    if (message === '' || typeof message !== 'string') {
      reject('Message is empty or not a string');
    } else {
      setTimeout(() => {
        resolve(message);
      }, 1500);
    }
  });
}

timeoutPromise("")
.then((m)=>console.log(m))
.catch((e)=>console.error(e))

async/await

함수의 선언 앞에 async 를 넣으면 비동기 함수로 전환된다.

async함수안에서는 promise API앞에 await 를 붙여 동기적으로 사용할 수 있게 한다.



🔎엄격모드

엄격모드를 사용함으로써 다음 변경사항이 발생된다.

  1. 기존에는 무시됐던 에러를 무시하지 않고 발생시킨다.
  2. 최적화 작업을 어렵게 만드는 실수를 없앤다.
  3. ECMAScript의 차기 버전들에서 정의 될 문법을 금지한다.

사용하는 방법은 구문 작성 전 제일 상단부에 “use strict”를 삽입하면 된다.
다만 모듈타입으로 자바스크립트를 사용하는 경우 자동으로 엄격모드가 적용되므로 따로 작성해줄 필요는 없다.


글로벌 변수 금지

mistypedVaraible = 17;

변수를 지정하지 않았지만 느슨한모드에서는 전역객체에 대한 새 속성을 만들어 그대로 동작시킨다.
엄격모드는 이 부분에서 Reference Error를 던진다.


실패된 동작에 예외를 발생

undefined를 변수로 지정하면 값을 할당할 수 없다. Infinity도 마찬가지다.
쓸 수 없는 변수에 값을 할당하는 것에 에러를 던진다.
뿐만 아니라 생성한 객체의 프로퍼티 등 모든 실패에 에러를 던진다.

var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // TypeError 발생

var obj2 = { get x() { return 17; } };
obj2.x = 5; // TypeError 발생

함수 인자의 유일성

함수의 파라미터의 이름이 유일하도록 요구한다.

function sum(a, a, c){ // !!! 구문 에러
  "use strict";
  return a + b + c; // 코드가 실행되면 잘못된 것임
}


🔎가비지콜렉션

가비지 컬렉션은 자바스크립트가 객체가 생성되었을 때 자동으로 메모리를 할당하고 쓸모없어졌을 때 자동으로 해제하는 것을 의미한다.

메모리의 생존주기는 필요할 때 할당해서 사용한 뒤 필요없어지면 해제한다.

할당하고 해제하는 것은 저수준언어에서는 명시적으로 사용되지만 고수준 언어에서는 암묵적으로 작동한다.

자바스크립트는 값을 선언할 때 자동으로 메모리를 할당한다.


문제점

대부분의 문제는 할당된 메모리가 필요없어졌을 때 해제하는 것에서 발생한다.

자바스크립트는 가비지컬렉션이라는 자동 메모리 관리 방법을 사용하여 해제를 시킨다. 가비지 콜렉터의 목적은 메모리 할당을 추적하고 더 이상 필요하지 않는지를 판단하여 회수하는 것이다.

하지만 메모리가 여전히 필요한지를 판단하는 것은 비결정적 문제이기 때문에 좋지않다.

가비지 콜렉션 알고리즘은 참조를 핵심으로 동작한다. 다음 코드를 읽어보면 참조에 대한 쉽게 감을 잡을 수 있다.

var x = {
  a: {
    b: 2
  }
};
// 2개의 오브젝트가 생성되었다. 하나의 오브젝트는 다른 오브젝트의 속성으로 참조된다.
// 나머지 하나는 'x' 변수에 할당되었다.
// 명백하게 가비지 콜렉션이 수행될 메모리는 아직 하나도 없다.

var y = x;      // 'y' 변수는 위의 오브젝트를 참조하는 두 번째 변수이다.

x = 1;          // 이제 'y' 변수가 위의 오브젝트를 참조하는 유일한 변수가 되었다.

var z = y.a;    // 위의 오브젝트의 'a' 속성을 참조했다.
                // 이제 'y.a'는 두 개의 참조를 가진다.
                // 'y'가 속성으로 참조하고 'z'라는 변수가 참조한다.

y = "mozilla";  // 이제 맨 처음 'y' 변수가 참조했던 오브젝트를 참조하는 오브젝트는 없다.
                // (역자: 참조하는 유일한 변수였던 y에 다른 값을 대입했다)
                // 이제 오브젝트에 가비지 콜렉션이 수행될 수 있을까?
                // 아니다. 오브젝트의 'a' 속성이 여전히 'z' 변수에 의해 참조되므로
                // 메모리를 해제할 수 없다.

z = null;       // 'z' 변수에 다른 값을 할당했다.
                // 이제 맨 처음 'x' 변수가 참조했던 오브젝트를 참조하는
                // 다른 변수는 없으므로 가비지 콜렉션이 수행된다.

이 알고리즘을 Reference-counting 알고리즘이라 하는데 사실 더 이상 사용되지 않는다.

왜냐하면 순환참조를 이루는 경우에 한계가 발생하기 때문이다. 두 객체가 서로 참조하는 속성으로 생성되면 순환구조를 이루게 되는데 이 때문에 메모리 누수가 발생된다.

Mark-and-sweep알고리즘으로 이 문제를 해결한다.

이 알고리즘은 roots라는 객체(전역변수들의 집합)로부터 시작하여 roots가 참조하는 객체들을 닿을 수 있는 오브젝트라고 하며 그렇지 않은 것은 닿을 수 없는 오브젝트라고 하여 이것에 대해 가비지 콜렉션을 수행한다.

0개의 댓글