안녕하세요! 오늘은 JavaScript를 사용하여 달력을 구현하는 방법을 알아보겠습니다. 달력은 웹 개발에서 흔히 사용되는 UI 요소이며, 다양한 기능을 구현하는 데 활용될 수 있습니다.

1. 요일 계산

달력을 만들기 위해서는 먼저 각 달의 1일이 어느 요일인지 알아야 합니다. 이를 위해 getFirstDayIndex 함수를 정의합니다.

const getFirstDayIndex = (year, month) => {
  return (new Date(year, month, 1).getDay() + 6) % 7;
};

이 함수는 다음과 같이 작동합니다.

  1. new Date(year, month, 1): 해당 년, 월의 1일을 나타내는 Date 객체를 생성합니다.
  2. .getDay(): Date 객체의 요일을 가져옵니다. (0: 일요일, 1: 월요일, ..., 6: 토요일)
  3. + 6: 요일 값을 0부터 시작하도록 변환합니다.
  4. % 7: 7로 나눈 나머지를 계산하여 0부터 6 사이의 값을 얻습니다.

예를 들어, 2024년 3월 1일은 수요일입니다. 따라서 getFirstDayIndex(2024, 2) 함수는 3을 반환합니다.

 

2. 날짜 수 계산

다음으로 각 달의 날짜 수를 계산해야 합니다. 이를 위해 getDaysInMonth 함수를 정의합니다.

export const getDaysInMonth = (year, month) => {
  return new Date(year, month + 1, 0).getDate();
};

이 함수는 다음과 같이 작동합니다.

  1. new Date(year, month + 1, 0): 해당 년, 월의 다음 달의 0일을 나타내는 Date 객체를 생성합니다.
  2. .getDate(): Date 객체의 날짜를 가져옵니다.

예를 들어, 2024년 3월은 31일입니다. 따라서 getDaysInMonth(2024, 2) 함수는 31을 반환합니다.


달력도 고도화할 수 있는 여지가 많으며 구현 방법도 가지각색입니다. 다음 포스팅에서는 완성된 달력의 예시를 가져오면서 어떤 코드가 추가로 들어가는지 서술하겠습니다.

지난번 포스팅에 이어서 짧은 포스팅을 추가로 올리려고 한다.

지금 하는 작업은 하드 코딩에 가깝지만, 응용한다면 데이터를 가공하는데 도움이 될 것이라 생각한다.

// 데이터 가공해서 또 다른 Json 만들기 연습
// 학생, 학년, 학급, 학생 객체를 생성합니다.

let students = new Object();
let gradesX = new Object();
let classesX = new Object();
let studentX = new Array();

// 학생의 수만큼 k 변수로 반복문 돌립니다.
for(let k = 0; k<3; k++){
    let name = "";
    if( k%3 == 0 ){ name = "철수";
    }else if(k%3 == 1){ name = "영희";
    }else name = "동규";

    let studentIndex = {
        student_name : `${name}${k}`,
        student_height : Math.floor( (Math.random() * 120) ) + k,
        student_average : Math.floor( (Math.random() * 80) ) + k,
        student_report : 0 + k
    }
    
    studentX.push(studentIndex);
    
}  // k 변수 for문 종료

// classesX 객체에 key = student 에 value로 studentX 배열을 넣는다.
classesX.student = studentX;


// studentX 는 배열로 만들어둬서
/* classesX.student.description = "공부를 다들 열심히 합니다." */
// 와 같이 key, value를 추가할 수 없습니다.


// gradesX 객체에 key = class1 에 value로 바로 위의 classesX 객체를 넣는다. (객체 안에 객체 혹은 배열을 넣을 수 있다.)
gradesX.class1 = classesX;


// gradesX 객체에 key = class1 에 key가 teacher, 급훈인 value를 하나씩 넣는다. 우항은 string 값을 이용할 수 있어서 변수 혹은 for문 안에서도 가능하다.
gradesX.class1.teacher = "이민정쌤";
gradesX.class1.급훈 = "최선을 다하자";


// 위의 gradeX 객체를 students 객체의 key = grade1 의 value에 할당해준다.
students.grade1 = gradesX;

// 이외에 추가할만한 key, value를 할당해준다.
students.grade1.학주선생님 = "무서운 학주쌤";

// 아까 설정해둔 곳으로 접근해서 key, value 추가도 가능하다.
students.grade1.class1.특이사항 = "쉬는 시간엔 시끄럽지만 수업 때는 열심히 합니다.";


// 위와 비슷하게 학년 하나를 더 가공해봅니다.
// 원래라면 학생을 request로 얻어오던지 함수를 이용해서 다르게 하는게 맞지만 test를 위한 과정이라 같은 더미데이터를 사용하겠습니다.
let class2 = new Object();
class2 = classesX;
class2.teacher = "배용준쌤";
class2.급훈 = "잘생긴게 최고다";
students.grade1.class2 = class2;
students.description = "오지고 학생들";

console.log( JSON.stringify( students ) );

 

결과는 다음과 같다

{
  "grade1": {
    "class1": {
      "student": [
        {
          "student_name": "철수0",
          "student_height": 19,
          "student_average": 63,
          "student_report": 0
        },
        {
          "student_name": "영희1",
          "student_height": 57,
          "student_average": 25,
          "student_report": 1
        },
        {
          "student_name": "동규2",
          "student_height": 13,
          "student_average": 77,
          "student_report": 2
        }
      ],
      "teacher": "배용준쌤",
      "급훈": "잘생긴게 최고다",
      "특이사항": "쉬는 시간엔 시끄럽지만 수업 때는 열심히 합니다."
    },
    "학주선생님": "무서운 학주쌤",
    "class2": {
      "student": [
        {
          "student_name": "철수0",
          "student_height": 19,
          "student_average": 63,
          "student_report": 0
        },
        {
          "student_name": "영희1",
          "student_height": 57,
          "student_average": 25,
          "student_report": 1
        },
        {
          "student_name": "동규2",
          "student_height": 13,
          "student_average": 77,
          "student_report": 2
        }
      ],
      "teacher": "배용준쌤",
      "급훈": "잘생긴게 최고다",
      "특이사항": "쉬는 시간엔 시끄럽지만 수업 때는 열심히 합니다."
    }
  },
  "description": "오지고 학생들"
}

 

웹에서 데이터를 받고 전송을 한다면 json 형식과는 뗄레야 뗄 수가 없을 것이다.

지금까지는 간단한 형식의 json 파일만 사용해서 잘 몰랐던 점들이 있었는데, 오늘 연습해보고 기록하면서 json에 좀 더 잘 알 수 있기를 !!!

 

 배열만 이용한 json 만들기 연습

 

보통 이 경우는 이중 혹은 삼중, 그 이상의 배열을 다룰 때 쉽게 활용할 수 있다.

기본적으로 testArr[ i ][ j ][ k ] 이런 식으로 활용이 될 것이다.

예제 코드는 다음과 같다.

// 데이터 가공해서 또 다른 Json 만들기 연습
// Json 형식이 될 빈 리스트 생성
const student = new Array();

// 학년만큼 i 변수를 반복문 돌립니다.
for( let i = 0; i< 2; i++){
    // 학년 배열 생성
    let grades = new Array() ;
    
    // 학급의 수 만큼 j 변수를 반복문 돌립니다.
    for(let j = 0; j<4; j++){
        // 학급 배열 생성
        let classes = new Array() ;

        // 학생의 수만큼 k 변수로 반복문 돌립니다.
        for(let k = 0; k<3; k++){
            // 학생 객체 생성
            let students = new Object() ;
            if( k%3 == 0 ){
                students.student_name = `철수${i}${j}${k}`;
                students.student_height = Math.floor( (Math.random() * 120) ) + k;
                students.student_average = Math.floor( (Math.random() * 80) ) + k;
                students.student_report = 0 + k;
            }else if(k%3 == 1){
                students.student_name = `영희${i}${j}${k}`;
                students.student_height = Math.floor( (Math.random() * 120) ) + k;
                students.student_average = Math.floor( (Math.random() * 80) ) + k;
                students.student_report = 0 + k;
            }else{
                students.student_name = `동규${i}${j}${k}`;
                students.student_height = Math.floor( (Math.random() * 120) ) + k;
                students.student_average = Math.floor( (Math.random() * 80) ) + k;
                students.student_report = 0 + k;
            }
            
            classes.push(students);
        }
        grades.push(classes);
    }
    student.push(grades);
}

// 전체 학생
console.log("전체 학생");
console.log( JSON.stringify( student ) );

// 한 학년의 학생
console.log("한 학년의 학생");
console.log( JSON.stringify( student[0] ) );

// 한 반의 학생
console.log("한 반의 학생");
console.log( JSON.stringify( student[0][0] ) );

// 한명의 학생
console.log("한명의 학생");
console.log( JSON.stringify( student[0][0][0] ) );

 

결과

전체 학생
student_make_json.js:44
[[[{"student_name":"철수000","student_height":14,"student_average":73,"student_report":0},{"student_name":"영희001","student_height":72,"student_average":9,"student_report":1},{"student_name":"동규002","student_height":119,"student_average":62,"student_report":2}],[{"student_name":"철수010","student_height":101,"student_average":10,"student_report":0},{"student_name":"영희011","student_height":81,"student_average":67,"student_report":1},{"student_name":"동규012","student_height":114,"student_average":43,"student_report":2}],[{"student_name":"철수020","student_height":17,"student_average":75,"student_report":0},{"student_name":"영희021","student_height":14,"student_average":75,"student_report":1},{"student_name":"동규022","student_height":111,"student_average":39,"student_report":2}],[{"student_name":"철수030","student_height":59,"student_average":44,"student_report":0},{"student_name":"영희031","student_height":59,"student_average":45,"student_report":1},{"student_name":"동규032","student_height":96,"student_average":25,"student_report":2}]],[[{"student_name":"철수100","student_height":104,"student_average":28,"student_report":0},{"student_name":"영희101","student_height":87,"student_average":70,"student_report":1},{"student_name":"동규102","student_height":39,"student_average":3,"student_report":2}],[{"student_name":"철수110","student_height":88,"student_average":47,"student_report":0},{"student_name":"영희111","student_height":42,"student_average":23,"student_report":1},{"student_name":"동규112","student_height":44,"student_average":6,"student_report":2}],[{"student_name":"철수120","student_height":102,"student_average":19,"student_report":0},{"student_name":"영희121","student_height":119,"student_average":41,"student_report":1},{"student_name":"동규122","student_height":83,"student_average":49,"student_report":2}],[{"student_name":"철수130","student_height":11,"student_average":15,"student_report":0},{"student_name":"영희131","student_height":97,"student_average":46,"student_report":1},{"student_name":"동규132","student_height":121,"student_average":71,"student_report":2}]]]
student_make_json.js:45
한 학년의 학생
student_make_json.js:48
[[{"student_name":"철수000","student_height":14,"student_average":73,"student_report":0},{"student_name":"영희001","student_height":72,"student_average":9,"student_report":1},{"student_name":"동규002","student_height":119,"student_average":62,"student_report":2}],[{"student_name":"철수010","student_height":101,"student_average":10,"student_report":0},{"student_name":"영희011","student_height":81,"student_average":67,"student_report":1},{"student_name":"동규012","student_height":114,"student_average":43,"student_report":2}],[{"student_name":"철수020","student_height":17,"student_average":75,"student_report":0},{"student_name":"영희021","student_height":14,"student_average":75,"student_report":1},{"student_name":"동규022","student_height":111,"student_average":39,"student_report":2}],[{"student_name":"철수030","student_height":59,"student_average":44,"student_report":0},{"student_name":"영희031","student_height":59,"student_average":45,"student_report":1},{"student_name":"동규032","student_height":96,"student_average":25,"student_report":2}]]
student_make_json.js:49
한 반의 학생
student_make_json.js:52
[{"student_name":"철수000","student_height":14,"student_average":73,"student_report":0},{"student_name":"영희001","student_height":72,"student_average":9,"student_report":1},{"student_name":"동규002","student_height":119,"student_average":62,"student_report":2}]
student_make_json.js:53
한명의 학생
student_make_json.js:56
{"student_name":"철수000","student_height":14,"student_average":73,"student_report":0}

 

기왕에 연습겸 만들어본거 헷갈리던 개념도 한번 시험해보았다.

Js에서 for of과 for in 구문의 차이점을 실제로 체감하기가 힘들었는데 오늘의 예제가 도움이 되었다.

 

// 1학년 1반의 모든 학생 출력
console.log("1학년 1반의 모든 학생 출력");
for( let i = 0; i < student[0][0].length; i++ ){
    console.log( JSON.stringify( student[0][0][i] ) );
}

/** 결과
{"student_name":"철수000","student_height":49,"student_average":13,"student_report":0}
student_make_json.js:63
{"student_name":"영희001","student_height":97,"student_average":77,"student_report":1}
student_make_json.js:63
{"student_name":"동규002","student_height":88,"student_average":21,"student_report":2}
*/



// student[0][0] 을 변수화 시킨 후 1학년 1반의 모든 학생 출력
console.log("student[0][0] 을 변수화 시킨 후 1학년 1반의 모든 학생 출력");
let temp = student[0][0];
for( let i = 0; i < temp.length; i++ ){
    console.log( JSON.stringify( temp[i] ) );
}

/** 결과
{"student_name":"철수000","student_height":49,"student_average":13,"student_report":0}
student_make_json.js:70
{"student_name":"영희001","student_height":97,"student_average":77,"student_report":1}
student_make_json.js:70
{"student_name":"동규002","student_height":88,"student_average":21,"student_report":2}
*/



// 반복문을 출력하는 여러가지 방법 중 하나, for of 구문
console.log("반복문을 출력하는 여러가지 방법 중 하나, for of 구문");
temp = student[0][0];
for( let item of temp ){
    console.log( JSON.stringify( item ) );
    console.log( item );
}

/** 결과
{"student_name":"철수000","student_height":49,"student_average":13,"student_report":0}
student_make_json.js:77
{student_name: '철수000', student_height: 49, student_average: 13, student_report: 0}
{"student_name":"영희001","student_height":97,"student_average":77,"student_report":1}
student_make_json.js:77
{student_name: '영희001', student_height: 97, student_average: 77, student_report: 1}
{"student_name":"동규002","student_height":88,"student_average":21,"student_report":2}
student_make_json.js:77
{student_name: '동규002', student_height: 88, student_average: 21, student_report: 2}
*/



// 반복문을 출력하는 여러가지 방법 중 하나, for in 구문
console.log("반복문을 출력하는 여러가지 방법 중 하나, for in 구문");
temp = student[0][0];
for( let item in temp ){
    console.log( JSON.stringify( item ) );
    console.log( item );
}

/** 결과
"0"
student_make_json.js:85
0
student_make_json.js:86
"1"
student_make_json.js:85
1
student_make_json.js:86
"2"
student_make_json.js:85
2
*/

 

이 외에도 맨 위에 동일한 작업이 반복되는 코드를 함수화 시켜서 할 수도 있습니다.

// 데이터 가공해서 또 다른 Json 만들기 연습
// Json 형식이 될 빈 리스트 생성
const student = new Array();

let makeStudentObject=( students, i, j, k )=>{
    let name = "";
    if( k%3 == 0 ){ name = "철수";
    }else if(k%3 == 1){ name = "영희";
    }else name = "동규";
    students.student_name = `${name}${i}${j}${k}`;
    students.student_height = Math.floor( (Math.random() * 120) ) + k;
    students.student_average = Math.floor( (Math.random() * 80) ) + k;
    students.student_report = 0 + k;
    return students;
}

// 학년만큼 i 변수를 반복문 돌립니다.
for( let i = 0; i< 2; i++){
    // 학년 배열 생성
    let grades = new Array() ;
    
    // 학급의 수 만큼 j 변수를 반복문 돌립니다.
    for(let j = 0; j<4; j++){
        // 학급 배열 생성
        let classes = new Array() ;

        // 학생의 수만큼 k 변수로 반복문 돌립니다.
        for(let k = 0; k<3; k++){
            classes.push( makeStudentObject( new Object() , i, j, k ));
        }
        grades.push(classes);
    }
    student.push(grades);
}

/** 결과
[[[{"student_name":"철수000","student_height":85,"student_average":79,"student_report":0},{"student_name":"영희001","student_height":46,"student_average":34,"student_report":1},{"student_name":"동규002","student_height":47,"student_average":18,"student_report":2}],[{"student_name":"철수010","student_height":118,"student_average":13,"student_report":0},{"student_name":"영희011","student_height":33,"student_average":28,"student_report":1},{"student_name":"동규012","student_height":95,"student_average":13,"student_report":2}],[{"student_name":"철수020","student_height":53,"student_average":6,"student_report":0},{"student_name":"영희021","student_height":26,"student_average":80,"student_report":1},{"student_name":"동규022","student_height":112,"student_average":59,"student_report":2}],[{"student_name":"철수030","student_height":71,"student_average":64,"student_report":0},{"student_name":"영희031","student_height":69,"student_average":23,"student_report":1},{"student_name":"동규032","student_height":74,"student_average":24,"student_report":2}]],[[{"student_name":"철수100","student_height":47,"student_average":30,"student_report":0},{"student_name":"영희101","student_height":36,"student_average":66,"student_report":1},{"student_name":"동규102","student_height":109,"student_average":21,"student_report":2}],[{"student_name":"철수110","student_height":39,"student_average":71,"student_report":0},{"student_name":"영희111","student_height":104,"student_average":17,"student_report":1},{"student_name":"동규112","student_height":102,"student_average":41,"student_report":2}],[{"student_name":"철수120","student_height":57,"student_average":29,"student_report":0},{"student_name":"영희121","student_height":22,"student_average":15,"student_report":1},{"student_name":"동규122","student_height":35,"student_average":15,"student_report":2}],[{"student_name":"철수130","student_height":30,"student_average":72,"student_report":0},{"student_name":"영희131","student_height":111,"student_average":41,"student_report":1},{"student_name":"동규132","student_height":105,"student_average":70,"student_report":2}]]]
*/

 

오늘은 json 을 활용해서 해볼 수 있는 간단한 활용과 예제에 대해서 알아보았습니다.

https://codebeautify.org/jsonviewer

 

Best JSON Viewer and JSON Beautifier Online

Online JSON Viewer, JSON Beautifier and Formatter to beautify and tree view of JSON data - It works as JSON Pretty Print to pretty print JSON data.

codebeautify.org

와 같은 사이트에서 json을 보기 좋게 변환해서 볼 수도 있고,

이외에도 json prettifier 라고 구글에 치시면 비슷한 역할을 하는 웹사이트가 이미 많이 서비스 되고 있습니다.

이와 같이 json 파일이 현재 어떻게 되어 있는지 확인할 수 있습니다.

 

반복문으로 배열을 생성하고 json 화 시키려고 할 때 key에 string 값을 줄 수가 없어서 

명시적으로 하다보면 하드코딩이 되어버리곤 합니다.

이번에 사용하듯이 그냥 배열만 가지고 이용하면서 index 값을 통해 운영한다면 훨씬 쾌적하고 빠르게 코딩할 수 있습니다.

※ 이 코드는 정답이 아니고, 집단지성의 힘을 빌려 재구성한 코드입니다! 이와 같은 방식을 구현하는 방법은 많습니다.

/**
 * scrollAnimation 설명서
 * 이 메서드는 화면(window)의 스크롤에 맞춰 특정 요소에
 * 이벤트(show, hide, transform) 를 줄 수 있습니다.
 * 제이쿼리 임포트를 필수로 요구합니다.
 * show_and_hide 클래스를 이벤트를 적용할 오브젝트에 적용하면 됩니다.
 * _checkPosition에 add, remove에 있는 클래스는 자기 상황에 맞게 바꾸면 됩니다.
 */
const scrollAnimation=()=>{
    // items는 나중에 querySelectorAll을 사용할 때 쓸 수 있습니다
    // actionHeight는 가로 길이로 얼마나 스크롤했을 때 이벤트가 발동할지
    let items, actionHeight;

    // 페이지가 로드될 때 아이템에 쿼리셀렉터를 실행하고
    // actionHeight
    const initModule=()=>{
        items = document.querySelectorAll(".show_and_hide");
        actionHeight = 600;
        _addEventHandlers();
    };

    const _addEventHandlers=()=>{
        window.addEventListener("scroll", _checkPosition);
        window.addEventListener("load", _checkPosition);
        window.addEventListener("resize", initModule);
    };

    const _checkPosition=()=>{
        // 현재 윈도우의 스크롤 위치를 변수화 시킵니다.
        let here = window.scrollY;
        // if 조건일 때 사라지게 하고
        if(here>actionHeight){
            $('.show_and_hide').removeClass('show').addClass('hide');  
        }else{
            // else 조건일 때 보여지게 하는 코드입니다.
            $('.show_and_hide').removeClass('hide').addClass('show');
        }
    }
    return {
        init: initModule
    }
}

// 함수 초기화를 시켜줍니다.
scrollAnimation().init();

 

밑에 부분에서는 쿼리셀렉터를 이용한 구문이 없지만 원래 코드에서 쓰던 구조를 변형해서 제이쿼리로 특정 분기를 잡아서 클래스를 주고 사라지게 하는 방식을 채택했습니다.

CSR, 클라이언트 사이드 랜더링, 이하 csr
SSR, 서버 사이드 랜더링, 이하 ssr

두 개념을 이야기하기 전에 앞서 랜더링과 스태틱 랜더링에 대해서 찾아보면 더욱 좋습니다.



csr은 사이트에 접속하게 되면 서버에게서 인덱스 파일(html)을 받아오고

html에 적혀져 있는 js를 요청합니다.

최종적으로는 동적으로 html을 생성할 수 있는 자바스크립트 파일을 받아오게 됩니다.

"app.js를 로드한 순간"부터 사용자에게 웹페이지가 보여지게 되고

그때부터 클릭이나 interactive한 이용이 가능해짐


결국 이 말은

TTV와 TTI가 동시에 이뤄진다는 뜻입니다.

TTV는 Time To View의 약자,

TTI는 Time To Interactive의 약자입니다.

웹페이지인데 하나의 어플리케이션을 사용하는 것처럼 거의 즉각적으로 웹페이지와 유저가 interactive하게 통신할 수 있기 때문에 사용 경험에서는 더 좋은 유저 경험을 만들어 줄 수 있습니다.

대신 csr도 완벽하진 않습니다.

가장 치명적인 csr의 단점으로는 첫 로드가 오래 걸린다는 점을 꼽을 수 있습니다.

이외에도 SEO(검색 엔진 최적화) 등의 이슈가 있습니다.

 


ssr은 
사이트에 접속을 하게되면

서버에서 이미 만들어둔 index 파일을 받아오게되고

이 시점부터 사용자가 볼 수 있습니다

즉, TTV가 이때에 일어난다는 뜻입니다.

유저들이 볼 수 있는 
서버에서 이미 만들어진 index.html을 서버에서 받은 이후에

추가적으로 서버에서 필요한 js들,
예를 들자면 app.js 등을 받아야와야지만
interactive한 이용이 가능해집니다.

사용자가 볼 수 있는 시간과

실제로 interaction을 할 수 있는 시간의 차이가 존재합니다.

ssr의 단점으로 나타날 수 있는 현상으로는

웹어플리케이션 이용시 깜빡임 현상
(메뉴 하나를 눌러도 서버로부터 다시 html부터 로드하기 때문)
이 있겠습니다.

 

이렇게 차이가 나는 가장 큰 이유는

CSR은 유저에게 처음 Content를 보여주기까지의 과정이 많고,

SSR은 유저에게 Content를 보여주기까지의 과정이 동일합니다.

CSR의 과정을 살펴보면

DOWNLOAD HTML -> DOWNLOAD JAVASCRIPT -> EVALUATE JAVASCRIPT -> FETCH DATA FROM JAVASCRIPT    ->USER SEE CONTENT의 과정으로 되어 있는데

SSR의 과정으로는

DOWNLOAD HTML -> USER SEE CONTENT

HTML을 받자마자 content를 볼 수 있기 때문에 그렇습니다.




csr의 경우는
처음으로 로드하는 페이지의 데이터 양에 대해서 고민을 해보면 좋을 것이고,

ssr의 경우는
어떻게 좀 더 매끄러운 ui ux 유저 경험을 제공할 수 있을지 고민을 해보면 좋습니다.

예전에 가지고 놀던 프로젝트에서는 CSR 환경이었는데, 첫 페이지를 로드하면서

어딘가로 이동하는 듯한 느낌의 jpg 움짤을 만들어두고 그 곳에서 최소한 0.5초 이상 머무르게 하는 방법으로

첫 로딩이 되기까지 유저가 좀 지루해할 수 있는 시간을 단축시키고자 노력했었습니다.

 

csr환경을 구축하느냐 ssr환경을 구축하느냐 고민을 할 때 

우리가 만들 페이지는 동적인 편인가 정적인 편인가?

얼마나 되는 이용자가 우리의 서비스를 이용할 것으로 예상되는가?

등과 같은 질문에 대한 답변을 생각해보아야합니다.




리액트는 가상돔을 이용하여 csr에 특화된 라이브러리이지만
Gatsby라는 라이브러리를 사용한다면

정적으로 웹페이지를 미리 생성해두어서 서버에 배포해놓을 수 있습니다.

이는 완전히 정적인페이지가 아니라 JS 파일을 함께 가지고 있을 수 있기 때문에

동적이기도 합니다.



리액트와 Next.JS도 많이 사용된다고 합니다.

Next.JS는 강력한 ssr 라이브러리였으나,

CSR과 SSR의 장점을 합친 방식이라고 볼 수 있습니다.

리액트 18버전 부터는 다른 라이브러리의 도움 없이 리액트로도 SSR이 가능하다고 들었는데,

이에 대해서는 추가적으로 프로젝트를 하면서 공부해볼 계획입니다.

문제 설명
두 문자열 s와 skip, 그리고 자연수 index가 주어질 때, 다음 규칙에 따라 문자열을 만들려 합니다. 암호의 규칙은 다음과 같습니다.

문자열 s의 각 알파벳을 index만큼 뒤의 알파벳으로 바꿔줍니다.
index만큼의 뒤의 알파벳이 z를 넘어갈 경우 다시 a로 돌아갑니다.
skip에 있는 알파벳은 제외하고 건너뜁니다.
예를 들어 s = "aukks", skip = "wbqd", index = 5일 때, a에서 5만큼 뒤에 있는 알파벳은 f지만 [b, c, d, e, f]에서 'b'와 'd'는 skip에 포함되므로 세지 않습니다. 따라서 'b', 'd'를 제외하고 'a'에서 5만큼 뒤에 있는 알파벳은 [c, e, f, g, h] 순서에 의해 'h'가 됩니다. 나머지 "ukks" 또한 위 규칙대로 바꾸면 "appy"가 되며 결과는 "happy"가 됩니다.

두 문자열 s와 skip, 그리고 자연수 index가 매개변수로 주어질 때 위 규칙대로 s를 변환한 결과를 return하도록 solution 함수를 완성해주세요.

 

제한사항
5 ≤ s의 길이 ≤ 50
1 ≤ skip의 길이 ≤ 10
s와 skip은 알파벳 소문자로만 이루어져 있습니다.
skip에 포함되는 알파벳은 s에 포함되지 않습니다.
1 ≤ index ≤ 20

 

풀이

// skip 문자열을 먼저 분해하고 해석한다.
// 전체 알파벳에서 스킵할 문자열을 빼고 처리한다.

// 문자열을 분해해서 한글자 한글자 바꿔서 배열화 시킨 후에
// 그 배열을 돌려서 이미 작업이 끝난 알파벳 문자열을 이용해 인덱스만큼 움직인다.
// 1. 한글자를 뺀 후에 전체 배열에서 그 알파벳이 몇번째 index인지 찾는다.

let a_to_z;

let skip_arr = []

function make_a2z_zrr(){
    a_to_z = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
             'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
}

function split_sts( skip ){
    for(let i = 0; i<skip.length; i++){
        skip_arr.push(skip[i]);
    }
}

function compare_to_a2z(){
    for(let i = 0; i<a_to_z.length; i++){
        for(let j = 0; j<skip_arr.length; j++){
            if(skip_arr[j] === a_to_z[i]){
                delete a_to_z[i];
            }
        }
    }
}


function solution(s, skip, index) {
    var answer = '';
    make_a2z_zrr();
    split_sts( skip );  // skip 문자열 분해 완료
    compare_to_a2z();
    let new_alphabet = a_to_z.filter((element) => element !== undefined); 
    // a to z 에서 skip에 들어간 문자열을 뺌
    
    // 이제 s 문자열을 반복문에 넣고 돌린다.
    for(let i = 0; i<s.length; i++){
        let temp_index = new_alphabet.indexOf( s[i] )+index;
        while(temp_index>=new_alphabet.length){
            temp_index-=new_alphabet.length;
        }
        answer+=new_alphabet[temp_index];
    }

    
    return answer;
}

 

역할을 나눠서 문제를 풀면 훨씬 쉽고 빠르게 접근할 수 있는 듯 합니다.

+ Recent posts