[MGS 3기 - 12일차] JS Essentials

박철연·2022년 4월 26일
0

MGS STFE 3기

목록 보기
12/35
post-thumbnail

어제 자바스크립트의 기초를 학습한데 이어서, 오늘 강의에서는 좀 더 심화된 자바스크립트 지식을 다루었습니다.

Node.js

Node.js 개요

Node.js 는 구글 크롬의 자바스크립트 엔진(V8 Engine) 을 기반으로 만들어진 서버 사이드 플랫폼입니다.

웹 브라우저에서 동작하는 자바스크립트를 이용해 서버측에서 하는 역할을 수행할 수 있도록 하는 플랫폼이며, 이를 이용하면 PHP 나 JSP 의 역할을 대체할 수 있습니다.

Node.js는 여러가지 특징이 있는데, 첫 번째 특징은 라이브러리의 모든 API는 비동기 방식이라는 것입니다. 즉, 한 작업이 완료될 때까지 기다렸다가 작업하는 것이 아니라 멈추지 않고 계속해서 코드를 실행한다는 의미입니다.

또한 Node.js는 구글 크롬의 V8 자바스크립트 엔진을 사용하여 빠른 속도를 자랑합니다.

뿐만 아니라 Node.js는 하나의 쓰레드만을 사용하고 아파치와 같은 웹서버보다 훨씬 많은 요청을 처리할 수 있습니다.

nvm 사용법

nvm은 Node Version Manager의 약자로, 여러 가지 노드 버전을 관리하기 위한 도구입니다.

다양한 프로젝트를 접하다 보면, 서로 다른 버전의 노드 기반으로 프로젝트가 구성되는 경우가 있습니다.

이러한 상황에서 충돌이나 버전 호환등을 도와주는 것이 바로 nvm이라고 볼 수 있습니다.

$ brew install nvm

Mac OS를 사용한다면 위 명령어를 터미널에 입력하여 설치할 수 있습니다.

// zsh 설정 파일 열기
vi ~/.zshrc

...

// 추가할 내용
export NVM_DIR=~/.nvm
source $(brew --prefix nvm)/nvm.sh

또한 설치가 끝나고 나면, 위 코드를 통해 zshrc 파일에 nvm을 연결하는 과정을 거쳐야 합니다. (zsh 기준)

npm

npm은 Node Package Manager의 줄임말로 Node.js 기반 패키지(모듈)들을 모아둔 저장소입니다.

npm을 사용하면 프로젝트에 필요한 패키지들을 자유롭게 설치/제거할 수 있고, 업데이트도 가능해 집니다.

뿐만 아니라, 프로젝트에 포함된 패키지들의 의존성 관리도 할 수 있습니다.

의존성 관리

초기의 자바스크립트는 간단한 작업을 위해 만들어졌지만, 웹 기술이 빠르게 발전하면서 점점 더 복잡한 코드가 늘어났습니다.

때문에 코드를 기능이나 페이지 단위로 분리하고 있음에도, 코드간의 복잡한 의존 관계를 피할 수 없게 되었습니다.

npm 이전에는 script 태그를 통해 패키지의 의존성을 일일히 나열하고, 각각의 패키지 버전을 정확하게 유지해야 했기 때문에 비효율이 심했습니다.

하지만 npm은 package.json 파일을 생성해, 이 파일에 패키지의 상태나 의존성을 기록하기 때문에, 간편하게 의존성을 관리할 수 있습니다.

npm 설치

npm은 기본적으로 node.js를 설치할 때 자동으로 설치됩니다. 따라서 별도의 설치 과정이 필요하지 않습니다.

만약 npm이 제대로 설치되었는지 확인하고 싶다면, 아래 명령어로 확인 가능합니다.

$ node -v
$ npm -v

또한, 로컬 환경에 npm이 설치된 상태라면, 명령어를 통해 새로운 프로젝트를 npm의 관리 아래 두게끔 해주어야 npm을 활용할 수 있습니다. 해당 명령어는 아래와 같습니다.

npm init
npm init -y

y 플래그를 붙여서 npm init을 실행하면, 각종 세부 설정을 모두 스킵하고 즉시 npm init을 실행합니다.

유의적 버전

개발하는 프로젝트의 규모가 커지고 외부 라이브러리를 많이 사용할 수록 의존성 지옥에 빠지기 쉬워집니다. 라이브러리의 버전을 변경할 때 어떤 규칙에 의해서 버전이 매겨지는지 통용되는 명확한 규칙이 없기 때문입니다.

이를 해결하기 위해 고안된 방법론이 유의적 버전입니다. 아래의 규칙 하에 적용합니다.

  1. 외부에서 사용할 수 있는 공개 API 를 선언
  2. 라이브러리의 버전은 MAJOR.MINOR.PATCH 와 같은 형식으로 작성

기존 버전과 호환되지 않게 API가 변경되면 "MAJOR 버전"의 숫자를 올립니다.

기존 버전과 호환되면서 새로운 기능이 추가 되었을 때는 "MINOR 버전"의 숫자를 올립니다.

마지막으로, 기존 버전과 호환되면서 버그를 수정했을 경우 "PATCH 버전" 을 올립니다.

자바스크립트 활용

산술, 할당 연산자

자바스크립트 산술 연산자는 사칙연산과 나머지 연산을 말합니다.

+, - 기호는 덧셈과 뺄셈 연산을 진행합니다. *, / 기호는 곱셈과 나눗셈 연산을 진행합니다.

% 기호는 몫을 나눈 나머지를 결과로 반환합니다.

산술 연산자는 모두 두 개의 피연산자를 가지는 이항 연산자이며, 피연산자들의 결합 방향은 왼쪽에서 오른쪽입니다.

할당 연산자는 변수에 값을 대입할 때 사용하는 이항 연산자이며, 피연산자들의 결합 방향은 오른쪽에서 왼쪽입니다.

또한, 앞서 살펴본 산술 연산자와 결합한 다양한 복합 대입 연산자가 존재합니다.

비교, 논리 연산자

비교 연산자는 피연산자 사이의 상대적인 크기를 판단하여, 참(true)과 거짓(false)을 반환합니다.

비교 연산자는 모두 두 개의 피연산자를 가지는 이항 연산자이며, 피연산자들의 결합 방향은 왼쪽에서 오른쪽입니다.

자바스크립트에서 비교 연산자는 피연산자의 타입에 따라 두 가지 기준으로 비교를 진행합니다.

  1. 피연산자가 둘 다 숫자면, 해당 숫자를 서로 비교합니다.
  2. 피연산자가 둘 다 문자열이면, 문자열의 첫 번째 문자부터 알파벳 순서대로 비교합니다.

상세한 비교 연산자의 종류는 다음과 같습니다.

논리 연산자는 주어진 논리식을 판단하여, 참(true)과 거짓(false)을 반환합니다.

&& 연산자와 || 연산자는 두 개의 피연산자를 가지는 이항 연산자이며, 피연산자들의 결합 방향은 왼쪽에서 오른쪽입니다.

! 연산자는 피연산자가 단 하나뿐인 단항 연산자이며, 피연산자의 결합 방향은 오른쪽에서 왼쪽입니다.

삼항 연산자

삼항 연산자는 유일하게 피연산자를 세 개나 가지는 조건 연산자입니다.

삼항 연산자의 문법은 다음과 같습니다.

표현식 ? 반환값1 : 반환값2

물음표(?) 앞의 표현식에 따라 결괏값이 참이면 반환값1을 반환하고, 결괏값이 거짓이면 반환값2를 반환합니다.

삼항 연산자는 짧은 if / else 문 대신 사용할 수 있으며, 코드를 간결하게 만들어 줍니다.

반복문(for)

반복문이란 프로그램 내에서 똑같은 명령을 일정 횟수만큼 반복하여 수행하도록 제어하는 실행문입니다.

프로그램이 처리하는 대부분의 코드는 반복적인 형태가 많으므로, 가장 많이 사용되는 실행문 중 하나입니다.

자바스크립트에서 사용할 수 있는 반복문의 형태는 다양하나, 이번 정리글에서 다룰 반복문은 for 문입니다.

for 문은 while 문과는 달리 자체적으로 초기식, 표현식, 증감식을 모두 포함하고 있는 반복문입니다.

따라서 while 문보다는 좀 더 간결하게 반복문을 표현할 수 있습니다.

for 문의 문법은 다음과 같습니다.

for (초기식; 표현식; 증감식) {
표현식의 결과가 참인 동안 반복적으로 실행하고자 하는 실행문;
}

for 문을 구성하는 초기식, 표현식, 증감식은 각각 생략될 수 있습니다.

또한, 쉼표 연산자(,)를 사용하면 여러 개의 초기식이나 증감식을 동시에 사용할 수도 있습니다.

변수 유효 범위

자바스크립트에서 객체나 함수는 모두 변수(variable)입니다.

변수의 유효 범위(scope)란 해당 변수가 접근할 수 있는 변수, 객체 그리고 함수의 집합을 의미합니다.

자바스크립트에서 변수는 유효 범위에 따라 다음과 같이 구분됩니다.

  1. 지역 변수(local variable)
  2. 전역 변수(global variable)

지역 변수(local variable)

지역 변수(local variable)란 함수 내에서 선언된 변수를 가리킵니다.

이러한 지역 변수는 변수가 선언된 함수 내에서만 유효하며, 함수가 종료되면 메모리에서 사라집니다.

함수의 매개변수 또한 함수 내에서 정의되는 지역 변수처럼 동작합니다.

자바스크립트에서는 선언되지 않은 변수를 사용하려고 하거나 접근하려고 하면 오류를 발생시키나, 선언되지 않은 변수에 대한 typeof 연산자의 결괏값은 undefined 값을 반환합니다.

전역 변수(global variable)

전역 변수(global variable)란 함수의 외부에서 선언된 변수를 가리킵니다.

이러한 전역 변수는 프로그램의 어느 영역에서나 접근할 수 있으며, 웹 페이지가 닫혀야만 메모리에서 사라집니다.

전역 변수와 같은 이름의 지역 변수를 선언하면, 해당 블록에서는 해당 이름으로 지역 변수만을 호출할 수 있습니다.

형 변환(type conversion)

함수와 연산자에 전달되는 값은 대부분 적절한 데이터 타입으로 자동 변환됩니다. 이런 과정을 "형 변환(type conversion)"이라고 합니다.

문자, 숫자, 논리형으로의 형 변환은 자주 일어나는 형 변환입니다.

문자형으로 변환 은 무언가를 출력할 때 주로 일어납니다. String(value)을 사용하면 문자형으로 명시적 변환이 가능합니다.

원시 자료형을 문자형으로 변환할 땐, 대부분 그 결과를 예상할 수 있을 정도로 명시적인 방식으로 일어납니다.

숫자형으로 변환 은 수학 관련 연산시 주로 일어납니다. Number(value)로도 형 변환을 할 수 있습니다.

숫자형으로의 변환은 다음 규칙을 따릅니다.

Boolean으로 변환 은 논리 연산 시 발생합니다. Boolean으로의 형 변환은 다음 규칙을 따르는 데, 이것이 전 게시글에서 언급한 truthy, falsy 값이라고 볼 수 있겠습니다.

자바스크립트 함수

화살표 함수

화살표 함수(Arrow function)는 function 키워드 대신 화살표(=>)를 사용하여 보다 간략한 방법으로 함수를 선언할 수 있습니다.

화살표 함수의 기본 문법은 아래와 같습니다.

// 매개변수 지정 방법
    () => { ... } // 매개변수가 없을 경우
     x => { ... } // 매개변수가 한 개인 경우, 소괄호를 생략할 수 있다.
(x, y) => { ... } // 매개변수가 여러 개인 경우, 소괄호를 생략할 수 없다.

// 함수 몸체 지정 방법
x => { return x * x }  // single line block
x => x * x             // 함수 몸체가 한줄의 구문이라면 중괄호를 생략할 수 있으며 암묵적으로 return된다. 위 표현과 동일하다.

() => { return { a: 1 }; }
() => ({ a: 1 })  // 위 표현과 동일하다. 객체 반환시 소괄호를 사용한다.

() => {           // multi line block.
  const x = 10;
  return x * x;
};

화살표 함수는 익명 함수로만 사용할 수 있습니다. 따라서 화살표 함수를 호출하기 위해서는 함수 표현식을 사용해야 합니다.

또한 다른 함수의 콜백 함수로 작성하는 것도 가능합니다.

즉시 실행 함수

함수의 정의와 동시에 실행되는 함수를 즉시 실행 함수(IIFE, Immediately Invoke Function Expression)라고 합니다.

이러한 즉시 실행 함수는 최초 한번만 호출되며 다시 호출할 수가 없습니다.

이러한 특징을 이용하여 최초 한번만 실행이 필요한 초기화 처리등에 사용할 수 있습니다.

자바스크립트에서 가장 큰 문제점 중의 하나는 파일이 분리되어 있다하여도 글로벌 스코프가 하나이며 글로벌 스코프에 선언된 변수나 함수는 코드 내의 어디서든지 접근이 가능하다는 것입니다.

따라서 다른 스크립트 파일 내에서 동일한 이름으로 명명된 변수나 함수가 같은 스코프 내에 존재할 경우 원치 않는 결과를 가져올 수 있습니다.

즉시 실행 함수 내에 처리 로직을 모아 두면 혹시 있을 수도 있는 변수명 또는 함수명의 충돌을 방지할 수 있어 이를 위한 목적으로 즉시 실행 함수를 활용되기도 합니다.

// 기명 즉시 실행 함수(named immediately-invoked function expression)
(function myFunction() {
  let a = 3;
  let b = 5;
  return a * b;
}());

// 익명 즉시 실행 함수(immediately-invoked function expression)
(function () {
  let a = 3;
  let b = 5;
  return a * b;
}());

함수 호이스팅

아래 코드를 보면 함수 선언문으로 함수가 정의되기 이전에 함수 호출이 가능합니다.

const func = square(5);

function square(number) {
  return number * number;
}

함수 선언문의 경우, 함수 선언의 위치와는 상관없이 코드 내 어느 곳에서든지 호출이 가능한데 이것을 함수 호이스팅(Function Hoisting)이라 합니다.

함수 선언문으로 정의된 함수는 자바스크립트 엔진이 스크립트가 로딩되는 시점에 바로 초기화하고 이를 VO(variable object)에 저장합니다.

즉, 함수 선언, 초기화, 할당이 한번에 이루어지는 것입니다. 그렇기 때문에 함수 선언의 위치와는 상관없이 파일 내 어느 곳에서든지 호출이 가능해집니다.

다만, 함수 표현식의 방식으로 함수를 작성하는 경우에는 함수 호이스팅이 아니라 변수 호이스팅의 방식을 따릅니다.

타이머 함수

자바스크립트에서 사용하는 타이머 함수는 일정 시간이 지난 후 특정 코드 또는 함수가 실행될 수 있도록 해주는 함수와 일정 시간마다 함수가 실행될 수 있도록 해주는 함수를 말합니다.

일반적으로 아래 두 가지 유형의 타이머 함수를 자주 사용합니다.

  • setInterval & clearInterval
  • setTimeout & clearTimeout

setInterval / clearInterval

setInterval() 함수는 일정한 시간 간격으로 코드를 반복 실행하는 함수입니다.

setInterval() 함수로 넘기는 인자 정보는 2개입니다. 첫 번째 인자는 일정한 시간 간격으로 반복 실행하고자 하는 코드정보입니다.

두 번째는 시간 정보로 ms 단위로 설정합니다. 즉 1초 간격으로 코드를 실행하고 싶으면 1000으로 지정하면 됩니다.

반면에 clearInterval 함수는 생성한 타이머 함수를 제거하는 데 사용됩니다.

 const timer = setInterval(function(){
        console.log("Hello!!");
    }, 1000)

setTimeout / clearTimeout

setTimouout() 함수도 setInterval() 함수와 사용법은 같습니다.

다만 두 함수의 차이점은 setInterval() 함수는 시간 간격마다 코드를 실행시키고 반면에 setTimeout() 함수는 지정한 시간 간격에 코드가 딱 한 번만 실행이 된다는 것입니다.

const timer2 = setTimeout(function(){
        console.log("Hello World");
    }, 1000)

콜백 함수

콜백 함수는 다른 함수에 매개변수로 넘겨준 함수를 뜻합니다.

매개변수로 넘겨받은 함수는 일단 넘겨받고, 때가 되면 나중에 호출(called back)한다는 것이 콜백함수의 개념이라고 할 수 있겠습니다.

function plus(a, b, callback) {  
  let sum = a + b;
  callback(sum);
}      

콜백 함수 사용 원칙

콜백함수는 이름이 없는 '익명의 함수'를 사용합니다. 함수의 내부에서 실행되기 때문에 이름을 붙이지 않아도 되는 것입니다.

let number = [1, 2, 3, 4, 5];
number.forEach(function(x) {
console.log(x * 2);
});

자바스크립트는 null과 undefined 타입을 제외하고 모든 것을 객체로 다룹니다. 따라서 함수를 변수 혹은 다른 함수의 변수처럼 사용할 수 있습니다.

즉, 함수를 콜백함수로 사용할 경우, 함수의 이름만 넘겨주면 됩니다.

function whatYourName(name, callback) {
console.log('name: ', name);
callback();
}
function finishFunc() {
console.log('finish function');
}
whatYourName('Kim', finishFunc);

자바스크립트 클래스

프로토타입 객체

Java, C++과 같은 클래스 기반 객체지향 프로그래밍 언어는 객체 생성 이전에 클래스를 정의하고 이를 통해 객체(인스턴스)를 생성합니다.

하지만 자바스크립트같은 프로토타입 기반 객체지향 프로그래밍 언어는 클래스 없이(Class-less)도 객체를 생성할 수 있다.

자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있습니다.

그리고 이것은 마치 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있게 합니다.

이러한 부모 객체를 Prototype(프로토타입) 객체 또는 줄여서 Prototype(프로토타입)이라 합니다.

Prototype 객체는 생성자 함수에 의해 생성된 각각의 객체에 공유 프로퍼티를 제공하기 위해 사용합니다.

const student = {
  name: 'Lee',
  score: 90
};

// student에는 hasOwnProperty 메소드가 없지만 아래 구문은 동작합니다.
console.log(student.hasOwnProperty('name'));  // true
console.dir(student);

this

자바스크립트의 함수는 호출될 때, 매개변수로 전달되는 인자값 이외에, arguments 객체와 this를 암묵적으로 전달 받습니다.

function square(number) {

  console.log(arguments);
  console.log(this);
  return number * number;
}

square(2);

자바스크립트의 경우 함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정됩니다.

다시 말해, 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다는 것입니다.

아래에 각각의 호출 방법에 따른 this 바인딩 유형을 정리해보았습니다.

함수 호출

전역객체(Global Object)는 모든 객체의 유일한 최상위 객체를 의미하며 일반적으로 Browser-side에서는 window, Server-side(Node.js)에서는 global 객체를 의미합니다.

// in browser console
this === window // true

// in Terminal
node
this === global // true

메소드 호출

함수가 객체의 프로퍼티 값이면 메소드로서 호출됩니다.

이때 메소드 내부의 this는 해당 메소드를 소유한 객체, 즉 해당 메소드를 호출한 객체에 바인딩됩니다.

const obj1 = {
  name: 'Lee',
  sayName: function() {
    console.log(this.name);
  }
}

const obj2 = {
  name: 'Kim'
}

obj2.sayName = obj1.sayName;

obj1.sayName();
obj2.sayName();

생성자 함수 호출

new 연산자와 함께 생성자 함수를 호출하면 다음과 같은 방식으로 동작합니다.

클래스

모던 자바스크립트에 도입된 클래스(class)라는 문법을 사용하면 객체 지향 프로그래밍에서 사용되는 다양한 기능을 자바스크립트에서도 사용할 수 있습니다.

기본 문법은 다음과 같습니다.

class MyClass {
  // 여러 메서드를 정의할 수 있음
  constructor() { ... }
  method1() { ... }
  method2() { ... }
  method3() { ... }
  ...
}

이렇게 클래스를 만들고, new MyClass()를 호출하면 내부에서 정의한 메서드가 들어 있는 객체가 생성됩니다.

객체의 기본 상태를 설정해주는 생성자 메서드 constructor()는 new에 의해 자동으로 호출되므로, 특별한 절차 없이 객체를 초기화 할 수 있습니다.

profile
Frontend Developer

0개의 댓글