JS(Section 15. 코드 파일 다루기)

짜스의 하루 ·2024년 4월 30일

HTML에 불러오는 방법들

이러한 HTML코드가 있다고 가정해보자

cosole창에 document.querySelector('p'),innerText = '텍스트 변경해볼까?'를 입력 후, 실행해보면, <p>태그의 내용이 변경 된 것을 확인할 수 있다.

그럼 이러한 변경 방법을 자바스크립트로는 어떻게 해야 하는지 알아보자

1. 헤드에 스크립트로 로드

HTML 파일에 자바스크립트 파일을 로드하려면, 기본적으로 <head> 태그에
<script src = '파일 이름.js'></script>를 입력하면, 로드할 수 있다.
이후, 콘솔 창에서 했던 것처럼, 똑같이 실행시켜보면, 변경이 이루어지지 않는 것을 확인할 수 있다.

  • 스크립트 동작하지 않음 - 스크립트 로드 시점에는 body 요소가 로드되지 않았음
    --> 간단하게 설명하자면, 코드는 위에서 아래로 실행하게 되는데, <body> 태그가 실행하기 전에, 이미 자바스크립트 파일이 로드되기 때문에 변경이 이루어지지 않는 것이다.
  • 스크립트의 크기가 클 경우 그 아래 요소들의 로드가 지연됨 - 동기적 로드가 이루어진다.

2. body 요소들 아래에 로드
그럼 자바스크립트 파일을 body 요소 가장 아래에 배치하면 되지 않을까? 하고 생각할 수 있다.
실행을 시켜보면
변경이 완료된 것을 확인할 수 있다

하지만, 이러한 방식은 권장하지 않는다.

3. async / defer 로드

원래 자바스크립트 파일을 로드한 방식대로, <head> 태그에 스크립트 파일을 로드한 후, async, defer를 위와 같이 추가해보면 된다.

async 속성:

  • <script async> 를 사용하면 브라우저가 스크립트를 비동기적으로 로드한다. 이는 스크립트를 다운로드하는 동안에도 페이지의 해석 및 렌더링을 중단하지 않고 계속할 수 있다는 것을 의미한다.
  • 스크립트가 다운로드되면, 다운로드가 완료되는 즉시 스크립트가 실행된다.
  • 주의할 점은 스크립트가 다운로드되고 실행될 때의 순서가 보장되지 않는다. 다운로드가 빨리 완료될 경우, 실행도 빨리 시작되게 된다. 따라서 다운로드가 빨리 완료되어도 페이지의 다른 요소들이 모두 로드되기 전에 실행될 수 있다.
  • async 속성이 있는 스크립트는 HTML 파서가 다운로드를 발견하면 즉시 다운로드를 시작하고, 다운로드가 완료되면 바로 실행된다.

defer 속성:

  • <script defer>를 사용하면 브라우저가 스크립트를 비동기적으로 로드하지만, 페이지 해석과 렌더링을 지연시킨다.
  • 스크립트가 다운로드되면, HTML 파서는 다운로드를 발견하고 스크립트를 백그라운드에서 다운로드한다. 페이지 파싱은 계속 진행되지만 스크립트가 실행될 때까지 페이지 렌더링은 중단된다.
  • 일반적으로 <script> 태그의 순서대로 스크립트가 실행된다. 즉, 첫 번째 <script> 태그의 스크립트가 먼저 실행되고, 그 다음 태그의 스크립트가 실행된다.
  • defer 속성을 사용하면 스크립트가 페이지 로드가 완료된 후 실행될 것을 보장한다. 즉, DOMContentLoaded 이벤트가 트리거된 직후에 실행된다.

async 속성을 사용하면 스크립트가 다운로드되는 동안에도 페이지 렌더링이 계속되지만, 순서가 보장되지 않는다. 반면에 defer 속성이 있는 스크립트는 HTML 파일 파싱 중에 다운로드되지만, 스크립트의 실행은 HTML 파싱이 완료된 후에 이루어진다.


모듈과 라이브러리

⭐ 페이지에 자바스크립트 파일 여럿을 로드할 때 문제점들

1 . 네임스페이스 문제


두개의 스크립트 파일에 x를 정의해두고, 값을 다르게 주었다. 이후, 출력해보니

./script.js 파일의 x는 정상적으로 처리가 되었지만, ./script2.js 파일의 x는 오류가 발생했다 ( 오류 코드를 살펴보면, x는 이미 존재한다 를 의미한다).

  • 같은 상수나 변수명이 둘 이상의 파일에서 사용되었으므로 오류 발생
  • 다른 파일에 상수/변수명이나 함수명이 중복 사용되지 않았는지 확인해야 함
  • 규모가 큰 웹페이지를 분업하여 만들 때 특히 큰 어려움

2 . 파일의 순서 문제

이번에는 ./script.js 에는 x = 1를 명시해두고, ./script2.js 는 y = 2를 명시해두고, console.log(x,y)로 두가지 값을 모두 출력해보았다.

이후 출력 결과를 살펴보면, console.log(x,y)의 값이 ./script.js에서 명시한 x의 값이 출력되는 것을 확인할 수 있다.

그렇다면, 이렇게 스크립트 로드 코드의 순서를 변경해보면 어떨까?
오류가 발생한다.
이는 사실 오류가 발생하는 것이 옳다 --> ./script2.js 에는 x의 값이 명시되어 있지 않기 때문이다.

  • 다른 파일의 코드가 필요할 경우 순서에 의존적임
  • 한 파일의 코드가 다른 파일의 변수에 영향을 미칠 수 있음 --> 오류 위험
  • 결국 큰 .js 파일 하나를 나눠 작성하는 것에 불과

모듈 사용하기

모듈은 코드를 여러 파일로 나누고, 각 파일 간에 필요한 기능을 공유하기 위한 방법이다. 모듈은 일종의 코드 조각이며, 모듈 안에는 변수, 함수, 클래스 등이 포함될 수 있다.

  1. 기본 사용법

HTML 파일

  • 모듈로서 로드할 파일에는 type="module" 속성을 넣어줌
    ⭐ 모듈은 자동으로 defer로 로드됨
    ⭐ 실행코드가 들어있는 파일만 로드하면 된다.

script 파일

  • ⭐ export
    모듈 생성하기: 모듈을 생성할 때는 export 키워드를 사용하여 모듈에서 외부로 공개할 변수, 함수, 클래스 등을 선언한다.

  • ⭐ import
    다른 파일에서 모듈을 가져올 때는 import 키워드를 사용한다. 가져온 모듈의 변수, 함수, 클래스 등은 원하는 이름으로 사용할 수 있다.
    모듈의 요소들을 객체 디스트럭쳐링 방식으로 가져올 수 있다

이와 같이 원하는 이름으로 바꾸어 가져올 수 있다.

2 . 여러 모듈들을 가져와 사용하기

module2.js

export const add = (a, b) => a + b;
export const subt = (a, b) => a - b;
export const mult = (a, b) => a * b;
export const div = (a, b) => a / b;

module3.js

export class Bird {
  constructor (name, sound) {
    this.name = name;
    this.sound = sound;
  }
  fly () {
    console.log(`${this.name} ${this.sound} 비행중`);
  }
};

export class Eagle extends Bird {
  constructor (name, sound, prey) {
    super(name, sound);
    this.prey = prey;
  }
  hunt () {
    console.log(`${this.name} ${this.prey} 사냥중`);
  }
};

이렇게 두가지 모듈을 지정해주었다고 가정해보자.
이런 식으로 필요한 모듈만 지정해서 가져와서 사용할 수 있다.

3 . 하나의 모듈 객체로 묶어서 가져오기

  • module4.js 모듈에서 세 개의 함수를 정의하고 내보낸다.

  • isOdd : 주어진 숫자가 짝수인지를 확인하는 함수이다.

  • square: 주어진 숫자의 제곱을 계산하는 함수이다.

  • logResult: 결과를 콘솔에 로그로 출력하는 함수이다.

  • main.js에서는 module4.js 모듈을 가져와서 funcs라는 이름으로 전체 모듈을 가져온다.
    --> import * as funcs from ~~

  • funcs는 모듈 내에서 정의된 모든 함수와 변수들을 포함하는 객체이다.

  • funcs객체에서 .logResult()함수를 호출해서, 주어진 배열에서 짝수를 필터링하고, 그 수 중, 각 짝수를 제곱한 후에 이를 .map()을 통해 새로운 배열로 만든 후, .join()메서드를 통해 문자열로 변경 후, 콘솔에 결과를 출력합니다.

4 . ⭐ 모듈에서는 await을 바로 사용 가능
이와 같이 main.js 파일에 await 함수를 사용했다.
출력 결과를 살펴보면, 정상적으로 작동이 이루어진 것을 확인할 수 있다.

6 . Node.js에서 모듈 사용
⭐ package.json의 객체에 아래의 type 항목 추가 하면 된다.

{
  "type": "module"
}

이후 터미널로 실행시켜 보면,

⭐ 외부 라이브러리 로드
--> Big.js를 사용해보자
https://github.com/MikeMcl/big.js/ 에서 big.mjs 파일을 다운받은 후,
내 vscode에도 똑같이 big.mjs 파일을 만든 후, 내용을 복사해서 생성해준다.

  • import Big from './big.mjs'; : big.mjs 파일에서 Big 객체를 가져온다.

  • console.log(0.1 + 0.2, new Big(0.1).plus(0.2).toNumber()); :
    0.1 + 0.2를 먼저 평가하여 그 결과를 콘솔에 출력한다, JavaScript에서는 부동 소수점 숫자를 정확하게 나타내지 못할 수 있으므로, 이 부분의 결과는 0.30000000000000004 등의 근사값이 될 것이다.
    new Big(0.1).plus(0.2).toNumber()는 Big 객체를 생성하고 plus 메서드를 호출하여 0.1 + 0.2를 계산한 후, toNumber 메서드를 호출하여 결과를 숫자로 변환한 값을 콘솔에 출력한다. 이때, Big 객체는 big.mjs 파일에서 정의된 객체이다.

  • 이런식으로 쭉 코드를 작성해 나가면 된다 .

이후 , 아까와 같은 방식으로 node.js에 출력해보면,
이와 같은 결과를 얻을 수 있다.


웹팩과 바벨

(실무에서는 react 안에 초기 세팅되어 있는 것을 사용하기 때문에, 실제로 설정할 일은 드물긴 하지만, 어떻게 돌아가는지 알아보는 시간을 가져보자);

I. 웹팩 Webpack

  • 번들러 bundler --> 프로젝트에 사용되는 파일들을 하나 또는 소수의 파일들로 압축
  • 어플리케이션이 로딩 및 실행 속도 향상
  • 각종 플러그인과 옵션을 사용하여 코드를 다양한 방법으로 변환/압축 가능
  • 🧊 공식 사이트 보기
  • 동종/유사 제품: RollUp, Parcel, Gulp, Vite...

스크립트 파일을 웹팩을 적용시켜보자
0 . 소스 저장소 분리하기
--> src 폴더를 만들고 .js파일들 모두 이동

1 . 프로젝트에 웹팩 설치

npm install webpack webpack-cli --save-dev

2 . 웹팩 설정 파일
webpack.config.js 라는 파일을 만들어 웹팩에 대한 설정을 담은 파일을 지정시켜 놓는다.

const path = require('path');

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },

  // 💡 추가설정들
  watch: true, // 파일 수정 후 저장시 자동으로 다시 빌드
  experiments: {
    topLevelAwait: true // 모듈 await 가능하도록
  }
};
  • ./src/main.js 파일과, 연결된 모든 모듈들을 ./dist/main.js 파일로 통합하겠다는 의미이다.

3 . 빌드 명령 추가

"scripts": {
   "build": "webpack"
 },
  • "build": "webpack"은 npm 스크립트의 구문입니다. 이는 "build"라는 이름의 스크립트를 정의하고, 이 스크립트를 실행할 때에는 webpack 명령어를 실행하라는 것을 의미한다.

4 . 빌드 및 실행

npm run build
  • 터미널에 빌드를 실행하면 된다.

  • dist 폴더에 main.js 파일이 생긴 것을 확인할 수 있다.
    --> dist/main.js 파일은 src/main.js를 시작으로 의존하는 모든 모듈을 포함하고 있다. 이것이 바로 웹팩이 제공하는 모듈 번들링 기능의 핵심이다.
    --> 이러한 접근 방식을 통해 여러 개의 파일을 합쳐서 하나의 파일로 만들어줌으로써 웹 애플리케이션의 성능을 향상시키고 관리를 용이하게 할 수 있다.

II. 바벨

  • 자바스크립트를 보다 오래된 환경에서 동작할 수 있는 버전으로 컴파일
  • 기타 방법: 타입스크립트 컴파일러 사용

바벨 사이트에서 사용해보았다.
익스플로어 11 버전으로 설정해두고, 현재 사용하는 자바스크립트 문법을 사용한 결과가 오른쪽에 출력되는 것을 확인할 수 있다.

2 . 웹팩 프로젝트에 적용해보기

npm install --save-dev babel-loader @babel/core @babel/preset-env

관련 모듈을 설치해주어야 한다.

이후, webpack.config.js에 아래의 프로퍼티들 추가하면 된다.

target: ['web', 'es5'], // ⭐ ES5 이하로 해야 할 시 필요
 module: {
   rules: [
     {
       test: /\.m?js$/,
       exclude: /node_modules/,
       use: {
         loader: 'babel-loader',
         options: {
           presets: [
             ['@babel/preset-env', { targets: "ie 11" }]
           ]
         }
       }
     }
   ]
 }

3 . 빌드하고 결과 확인

npm run build

JSDoc

⭐ JSDoc

  • 자바스크립트 코드에 주석을 달기 위한 🔗 마크업 언어
  • 에디터, IDE에서는 작성된 내용에 따라 코드 힌팅 등의 기능 제공
  • 👉 마치 타입스크립트 등의 언어처럼 인자 등의 자료형 제안 - 강제되지는 않음
  • 도구를 통해 웹 문서 등으로 출력될 수 있음

기본 주석

@type - 자료형 명시, @const - 상수임 명시

@param - 인자

@typedef, @property - 커스텀 객체 타입 지정

  • @typedef: 사용자 정의 타입을 정의하는 데 사용된다. 주로 객체나 복잡한 자료구조의 타입을 정의할 때 사용된다.
  • @property: 객체의 속성을 문서화하는 데 사용된다.--> 객체의 각 속성에 대한 설명과 타입을 제공한다 :
  • @param : 함수의 각 매개변수에 대한 설명과 타입을 제공한다.

@constructor, @class - 생성자 용도로 작성된 함수, 클래스

  • new 키워드와 함게 사용하여 객체를 생성함
  • 클래스의 생성자에는 @constructs

@todo - 이후 해야 할 일 표시 (실무에서 종종 사용)

@readonly - 읽기 전용 (강제성 없음)

@deprecated - 사라지게 될 기능

문서 생성해보기

  • API 문서 생성기 🔗 JSDoc 사용
  • ⭐ 프로젝트 디렉토리에 _로 시작하는 폴더가 포함되지 않아야 한다 - 위 생성기의 버그

1 . Node.js 환경에 JSDoc 설치

npm install -g jsdoc

2 . 문서 생성

jsdoc ./
  • 혹은 ./ 대신, 대상 .js파일의 경로 지정

실행시키면, out이라는 폴더에 파일들이 생성된 것을 확인할 수 있다.


이후 index.html파일을 라이브서버로 열어서 확인해보면,
이렇게 내가 작성해둔 JBDoc를 확인할 수 있다.


디버깅

: 디버깅은 자바스크립트 코드에서 발생하는 오류를 찾고 수정하는 과정을 나타낸다.
VS Code의 디버깅 툴로 다양한 디버깅의 기능을 조작해보자

1. 기본 디버깅

처음으로 실행 및 디버그를 누른 뒤, node.js로 실행시켜보면, 결과값이 출력되는 것을 확인할 수 있다.

  • 이제 🔴 표시된 라인들에 Breakpoint 브레이크포인트 달아보자

디버깅을 실행해보자, 이러한 화면이 나타나면서, 다양한 기능들로 디버깅을 실행할 수 있다.

위의 다양한 화살표의 기능을 살펴보면

  • Continue : 다음 브레이크포인트로 건너뜀
  • Step Over : 다음 라인으로 넘어감
  • Step Into (들어가기): 현재 줄에서 함수 호출로 이동하며, 함수 내부로 들어간다.
  • Step Out (나가기): 현재 함수의 실행이 완료될 때까지 실행을 계속한 후, 호출한 곳으로 돌아간다.
  • Restart (다시 시작): 디버깅 세션을 다시 시작한다.
  • Stop (중지): 디버깅 세션을 중지하고 실행을 멈춘다.
    x
    💡 VARIABLES 섹션에서 변수들의 값 확인할 수 있으며, 현재 코드에서는 Math.random()을 통해 x,y의 값을 랜덤으로 부여했기 때문에, 실행할 때마다, 값이 수동으로 변경되는 것을 확인할 수 있다.

2. 함수로 진입하기

  • 함수를 실행하는 라인에서 Step Into를 사용하여 함수로 진입이 가능하다.
  • 👉 모든 라인을 확인하려면 Step Into로 모두 진행해도 무관하다.
  • Step Out을 사용하여 빠져나올 수 있다.
    함수 내에 브레이크포인트가 걸려 있다면 Step Into하지 않아도 진입
    💡 CALL STACK 섹션에서 함수 호출마다의 스택 확인하기

    함수를 호출할 때, 스택의 이름들이 변경되는 것 또한 확인할 수 있다.
  • 💡 VARIABLES 섹션에서 각 스택에 속한 변수, this 값 확인하기

3. 오류와 예외처리된 사항 확인하기
Caught Exceptions 테스트
catch된 예외 체크온하고 오류 발생시킨 뒤 테스트해보기
체크를 하고 실행하게 되면, 라인을 쭉 실행하다가, catch문을 만나면 오류를 발생시키는 것을 확인할 수 있다.

4 . 특정 값 WATCH하기

  • x, y, dice를 조사식에 추가하고 테스트
  • !!(x % 2) 등의 표현식 넣어보기


디버깅 도구에서 조사식을 사용하여 변수의 값을 지정하는 기능은 주로 "조건부 중지점" 또는 "조건부 중단점"이라고 한다.

조건부 중단점을 사용하여 변수의 값을 지정할 때, 코드가 실행되는 것이 아니라 중단점이 설정된 위치에서만 해당 조건을 확인하고, 조건이 충족될 때만 코드가 일시 중지된다. 이렇게 중단된 상태에서 디버거 도구를 통해 변수의 값을 확인하거나 코드의 실행 흐름을 따라가며 디버깅을 수행할 수 있다.

Conditional Breakpoint 걸어보기

  • 🟡 표시된 라인에 dice < 3 조건의 Expression 브레이크포인트 걸어보기

  • 🟢 표시된 라인에 > 3 조건의 Hit Count 브레이크포인트 걸어보기

브라우저의 디버깅 툴

  • 라이브서버로 브라우저에서 실행
  • 개발자 도구에서 Sources 탭 열기
  • test.js 파일을 열기
  • 브레이크포인트들 추가한 뒤 새로고침하여 디버깅 시작
  • VS 코드에서 사용했던 기능들 시도해보기 - 전반적으로 유사
profile
2024. 01. 02 ~ 백앤드 공부 시작, 2024. 04.01 ~ 프론트 공부 시작

0개의 댓글