코드를 읽거나 작성할 때 일어나는 3가지 인지과정

 

새로운 프로그래밍 언어나 프레임워크를 배울 때, 익숙하지 않거나 자신이 오래 전에 작성한 코드를 볼 때, 그 코드가 무슨 일을 하는지 왜 그렇게 작성되었는지 이해가 안갈 수 있다. 코드를 처음 보게되었을 때 어떤 과정을 통해서 처리하게 되는지 3가지의 인지과정을 통해 알 수 있다.

 

1. 장기 기억공간(LTM)

오랜 시간 동안 저장한다는 점에서 컴퓨터의 하드 드라이브와 비슷하다.

장기기억공간에 해당 언어에 대한 지식이 없기 때문에 꺼내어 쓸 수 없는 것이다. 

장기 기억공간에 해당 지식이 없기 때문에 코드를 보았을 때 혼란이 발생할 수 있다. 

 

2. 단기 기억공간(STM)

단기 기억공간은 들어오는 정보를 잠시 보관하기 위해 사용된다. 

값을 일시적으로 저장하는 캐시나 메인 메모리라고 할 수 있다. 

 

3. 작업 기억 공간

정보를 처리하는 공간이다. 실제 사고작용이 일어나는 공간이다. 

작업 기억공간은 프로세서 역할이라고 볼 수 있다. 

우리는 코드를 읽을 때 머릿속에서 코드를 컴파일하고 실행하는 과정이 일어나는데 여기서 담당하는 역할이다. 

 

이 3가지의 인지 과정이 상호작용한다. 

코드를 보게되면 단기 기억공간이 받아들이는 정보가 들어오면 장기 기억공간의 지식이 더해져서

해당 코드가 무엇을 하는 역할인지 파악하는 일은 작업 기억 공간에서 이루어진다.

 

만약 새로운 버그가 리포트 되었다면, 단기 기억공간에 새로운 버그에 대한 정보가 기억된다.

장기 기억공간에 유사한 버그에 해결법이나 개인적인 기억이 존재한다면, 그 지식을 인출한다. 

이 두 기억공간과 함께 작업 기억공간(프로세서)에서 어떻게 처리할지 생각한다. 

예를 들면 "인덱스 값이 하나 작다." 같은 판단이 일어나는 것이다. 

 

코드를 읽는 동안 이 세 가지 과정이 함께 일어나며 보완적으로 작용한다. 

 

생소한 코드를 읽을 때 어려운 이유

알고리즘을 공부하다가 반복문이 여러개 중첩되거나 임시 변수가 계속 값이 바뀌는 경우에 머리로 계산을 하고자하는 경우, 적어보고 싶게 된다. 그 이유는 단기기억공간의 용량에 제한이 있기 때문이다. 일반적인 인가의 단기기억공간의 용량은 2개에서 6개라고 한다. 이 적은 용량을 극복하기 위해 장기기억공간과 협업하여 코드를 읽거나 이해하게된다. 

 

장기기억공간에 지식이 부족하면 코드를 읽을 때 하위 수준의 정보를에 의존해야하는데, 이때 단기기억공간이 빠르게 소진된다. 그래서 장기기억공간에 관련 지식을 충분히 가지고 있다면 추상 개념을 기억하기 때문에 단기기억공간을 덜 쓰고 인지과정이 일어날 수 있다. 그래서 관련 지식이 많을 경우  경우 코드를 더 빨리 이해하고 쓸 수 있다. 

 

 

인지과정을 높이기 위한 방법

지식을 늘리기(장기기억공간 활용)

특정한 주제에 대해 두뇌가 더 많은 정보를 저장하고 있다면 장기기억 공간에서 빠르게 꺼낼 수 있다. 단기 기억공간의 용량은 작기 때문에 장기 기억 공간을 활용하는 것이 더 좋다. 생소한 문자로 된 문장보다 우리가 이미 아는 단어로 된 문장이 기억하기 훨씬 쉬운 것과 같은 의미이다. 단어의 의미를 장기기억공간에서 인출하기 때문에 기억이 쉬운것이다. 그래서 장기기억공간에 지식이 많으면 기억을 쉽게 할 수 있다. 

 

기억하는 대상이 중요한게 아니고 기억하는 방식이 중요하다

읽기 쉬운 코드를 작성하기 위한 방법 중 하나로 얘기되는 것이 디자인 패턴 사용하기이다. 디자인 패턴을 사용하는 이유는 그룹으로 나누기 쉽기 때문이다. 또 그 이유는 두뇌에서 처리하기 쉽게되기 때문이다. '읽기 쉬운 코드를 작성해야하는 이유' = '인지 과정을 빠르게 하기 위해서' 이다. 디자인 패턴에 대한 지식을 가지게되면 청킹 능력(묶어서 기억할 수 있는 능력)이 향상되고 코드를 더 빠르게 수정할 수 있게 된다는 점이다. 

 

청킹 능력(묶어서 기억할 수 있는 능력)을 위한 의도적 연습

많은 사람들이 코드를 작성해보는 것으로 프로그래밍을 학습하는데 경우에 따라 효과적인 연습방법이 아닐 수도 있다. 청킹을 위해서는 코드를 의도적으로 기억해내는 연습을 하는 것이 좋다. 여러가지 방법이 있는데 여기서는 2가지를 제시한다. 

 

1. 반복적으로 학습하기

장기기억공간을 컴퓨터의 하드웨어로 예시를 들어 얘기했지만, 가장 큰 차이는 영원히 기억되지 않는 것이다. 비교적 오래 저장될 뿐. 그래서 정보를 다시 학습, 연습해주어야한다. 오랫동안 반복해서 학습하면 더 오래 기억한다. 더 많은 시간이 아니라 오랜 간격을 두고 학습해야한다는 것을 의미한다. 

 

두뇌의 기억은 네크워크 구조로 되어있다. 하나의 사실은 다른 많은 사실과 연관이 되어있다. 기존 기억에 새로운 지식을 적극적으로 연결시키는 정교화 작업이 필요하다. 원하는 정보에 대해 생각하는 과정을 정교화라고 한다. 두뇌에서 기억은 다른 기억과 사실을 연결하는 

연관 네트워크 형태이다. 정교화하면 네트워크는 강화된다. 

 

우리가 무엇을 기억해내려고할 때 분명히 아는 것인데 기억이 잘 나지않는다고 경험이 있을 것이다. 저장은 되어있지만 인출이 되지 않는 것이다. 장기 기억 공간의 어딘가에 저장되어있지만 그것을 필요할 때는 정작 가져오지 못하는 것이다. 인출은 시간이 흐를수록 약해진다. 이 때 정교화 작업이 필요한 것이다. 

 

2. 정교화를 이용해 프로그래밍 개념 학습하기

정교화는 기억하고자 하는 내용을 기존 기억과 연관지으면서 생각하는 것이고, 이것과 장기기억공간에 저장되어있는 스키마에 맞춰서 새로운 기억이 저장된다. 새로운 정보를 더 잘 기억하고 싶다면 그 정보를 정교화하자. 그것과 연관된 기억이 많을 수록 인출이 잘된다. 

 

정교화할 때 연습할 수 있는 질문

- 새로운 개념이 어떤 다른 개념을 생각나게 했는지?

- 공통점이 있는지?

- 비슷한 환경에서 사용될 수 있는지?

- 이미 알고있는 개념 대신에 사용될 수도 있는지

- 어떤 패러다임, 도메인, 라이브러리 혹은 프레임워크와 잘 맞을까?

'📓Book' 카테고리의 다른 글

Book | 그림으로 이해하는 네트워크 구조와 기술  (0) 2023.08.30
Book | 미라클모닝  (0) 2021.10.30

if-else 문제점

- 변경, 확장이 될 수록 코드가 복잡해진다.

- 코드를 수정하거나 수정할 위치를 찾는데 점점 오래걸린다.

- 실수로 추가하지않고 누락하는 부분이 생길 가능성이 있다.

즉, 유지보수가 점점 어려워진다.

 

OCP 개방 폐쇄 원칙

소프트웨어의 구성 요소(컴포넌트, 클래스, 모듈, 함수)는

확장에 대해서는 개방되어야하지만, 변경에 대해서는 폐쇄되어야 한다.

기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계가 되어야한다

 

점점 기능을 확장해 나갈 때, 기존의 코드를 계속 변경해야한다면 기능의 추가가 점점 힘들어지기 때문이다.  

기능이 추가, 변경되어도 기존 코드는 변경되지 않는다. (확장이 쉽다)

 

OCP 적용 방법

1. 상속을 이용한 방법 - 템플릿 메소드 패턴

깨지기 쉬운 상위 클래스 문제

 

 

2. 컴포지션을 이용한 방법 - 전략 패턴

상속보다는 컴포지션을 추천

1) 변경(확장)될 것과 변하지 않을 것을 구분 

변경되는 부분을 인터페이스로 추출

2) 이 두 모듈이 만나는 지점에 인터페이스 정의

인터페이스에 의존하도록 작성(기능 변경을 위해 코드를 수정해야하기 때문에)

3) 구현에 의존하기보다 정의한 인터페이스에 의존하도록 코드를 작성

 

자기가 직접 new 생성자로 인스턴스를 생성하지 않고, 외부에서 인스턴스를 받는 것을 의존성 주입(Dependency Injection, DI)이라고 한다.

 

Dependency Injection 의존성 주입
소프트웨어 개발에서 의존성 주입은 객체가 의존하는 다른 객체를 받는 것이다. 
의존성 주입의 의도는 객체의 생성과 사용의 관심을 분리하는 것이다. → 가독성과 코드 재사용을 높여준다.

소프트웨어 개발에서 의존성 주입은 객체가 의존하는 다른 객체를 받는 것이다. 
의존성 주입의 의도는 객체의 생성과 사용의 관심을 분리하는 것이다. → 가독성과 코드 재사용을 높여준다.

의존성 주입의 적용 유형
- 생성자 주입 : 필요한 의존성을 모두 포함하는 클래스의 생성자를 만들고, 그 생성자를 통해 의존성 주입
- setter를 통한 주입 : 의존성을 입력받는 setter 메소드를 만들고 이를 통해 의존성 주입
- 인터페이스를 통한 주입 : 의존성을 주입하는 함수를 포함한 인터페이스를 작성하고 이 인터페이스를 구현하도록 함으로써 실행 시에 의존성 주입

 

위키백과 의존성 주입

 

OCP를 준수하기 위한 디자인 패턴

전략패턴

전략패턴이란 기존의 코드 변경없이 행위를 자유롭게 바꿀 수 있게 해주는 OCP를 준수한 디자인 패턴 

 

디자인 패턴의 꽃

전략을 쉽게 바꿀 수 있도록 해주는 디자인 패턴

행위를 클래스로 캡슐화해 동적으로 행위를 자유롭게 바꿀 수 있게 해주는 패턴

새로운 기능의 추가가 기존의 코드에 영향을 미치지 못하게 하므로 OCP를 만족

 

 

참고자료

 

OCP(Open Closed Principle)이란?

 

nesoy.github.io

 

'🧐Programming' 카테고리의 다른 글

Servlet  (0) 2024.01.19
Java가 파일을 읽도록 하는 법  (0) 2024.01.14
Logging | SLF4J  (0) 2024.01.14
React | export와 export default의 차이  (0) 2023.08.12
Recoil | Selector  (0) 2021.12.01

Selector 

atom의 output을 변형시키는 함수로, atom에 의존하는 동적인 데이터를 만들 수 있게 해준다.

selecter는 get 함수와 set 함수를 사용할 수 있다. selector를 이용해 state를 가져와서 output을 수정할 수 있다. 

 

 

get

get: ({ get }) => {
	// 가져올 내용
	// get(가져올 값)
}

중괄호를 열고 쓰면 get이라는 함수를 다시 불러서 state를 가져올 수 있다. 그러면 어떤 값을 return 하던지 간에 그 값은 selector의 값이 된다. (atom을 가져와서 selector로 변경할 수 있다는 뜻)

get을 사용해 atom과 다른 selector에 접근 가능하다. 종속 관계가 생기므로 참조한 값이 업데이트 되면 해당 함수도 다시 실행된다.

 

set

set: ({ set }, newValue) => {
	// 변경내용
	// set(가져온 값, 변경(return)시킬 값)
}

set 함수는 변경될 새로운 값을 두 번째 인자로  받을 수 있다. 

 

 

 

예제

atom으로 minute를 생성하고, selector로 atom의 값을 가져와서 변경시키는 예제이다. '분'을 입력하면 '시간'으로 바꿔주고, '시간'을 입력하면 '분'으로 바꿔준다.

// atom.tsx

import { atom, selector } from 'recoil';

export const minuteState = atom({
  key: 'minute',
  default: 0,
});

export const hourSelector = selector<number>({
  key: 'hours',
  get: ({ get }) => {
    const minutes = get(minuteState);
    return minutes / 60;
  },
  set: ({ set }, newValue) => {
    const minute = Number(newValue) * 60;
    set(minuteState, minute);
  },
});
// App.tsx

import React from 'react';
import { useRecoilState, useRecoilValue, useRecoilValueLoadable } from 'recoil';
import { hourSelector, minuteState } from './atom';

function App() {
  const [minutes, setMinutes] = useRecoilState(minuteState);
  const [hours, setHours] = useRecoilState(hourSelector);
  const onMinutesChange = (event: React.FormEvent<HTMLInputElement>) => {
    setMinutes(+event.currentTarget.value);
  };
  const onHoursChange = (event: React.FormEvent<HTMLInputElement>) => {
    setHours(+event.currentTarget.value);
  };

  return (
    <div>
      <input
        value={minutes}
        onChange={onMinutesChange}
        type="number"
        placeholder="Minutes"
      />
      <input
        value={hours}
        onChange={onHoursChange}
        type="number"
        placeholder="Hours"
      />
    </div>
  );
}

export default App;

 

추가로 알게된 부분

string에 연산자 +를 붙이면 number로 형 변환이 가능하다. 

'🧐Programming' 카테고리의 다른 글

Servlet  (0) 2024.01.19
Java가 파일을 읽도록 하는 법  (0) 2024.01.14
Logging | SLF4J  (0) 2024.01.14
React | export와 export default의 차이  (0) 2023.08.12
OCP  (0) 2022.02.21

문제

현재 대기목록에 있는 문서의 중요도가 순서대로 담긴 배열 priorities와 내가 인쇄를 요청한 문서가 현재 대기목록의 어떤 위치에 있는지를 알려주는 location이 매개변수로 주어질 때, 내가 인쇄를 요청한 문서가 몇 번째로 인쇄되는지 return 하도록 solution 함수를 작성해주세요.

1. 인쇄 대기목록의 가장 앞에 있는 문서(J)를 대기목록에서 꺼냅니다.
2. 나머지 인쇄 대기목록에서 J보다 중요도가 높은 문서가 한 개라도 존재하면 J를 대기목록의 가장 마지막에 넣습니다.
3. 그렇지 않으면 J를 인쇄합니다.

제한사항

• 현재 대기목록에는 1개 이상 100개 이하의 문서가 있습니다.
• 인쇄 작업의 중요도는 1~9로 표현하며 숫자가 클수록 중요하다는 뜻입니다.
• location은 0 이상 (현재 대기목록에 있는 작업 수 - 1) 이하의 값을 가지며 대기목록의 가장 앞에 있으면 0, 두 번째에 있으면 1로 표현합니다.

 

필요 개념

배열에 값 추가 

unshift() : 배열의 맨 앞에 값 추가

push() : 배열의 맨 끝에 값 추가

배열에 값 제거

shift() : 배열의 맨 앞에 값 제거

pop() : 배열의 맨 뒤의 값 제거

 

풀이

출력횟수를 카운트할 변수 count

현재 위치 인덱스를 담고 변경해줄 변수 myDoc

 

while문으로 반복해서 배열을 돌면서 

현재 위치의 요소를 꺼낸 후(shift),

나머지 요소들과 비교해서 제일 높은 숫자라면 출력한다(카운팅). 만약 내 인덱스 변수가 0번째라면 answer에 담아서 리턴한다. 

나머지 요소들과 비교해서 현재 위치 요소보다 높은 숫자가 있다면, 꺼낸 요소를 배열의 맨 뒤에 다시 넣는다(push)

(이후 공통으로)

내 인덱스를 유지하기 위해 배열 내 이동이 있었으므로 -1씩해준다. 

만약 내 문서가 맨 뒤로 간 경우, 내 문서의 위치도 맨 뒤로 바꿔준다. 

 

코드

const solution = (priorities, location) => {
    let answer;
    let count= 0;
    let myDoc = location;
    
    while(priorities.length>0){
        let item = priorities.shift();
        if(priorities.filter((el) => el > item).length>0){
            priorities.push(item);
        } else {
            count++;
            if(myDoc === 0) {
                return answer = count;
            }
        }
        myDoc--;
        if(myDoc === -1){
            myDoc = priorities.length -1;
        }
    }
    
    return answer;
}

 

다른 풀이 코드

function solution(priorities, location) {
    let temp = [...priorities];
    let max = 0;
    let answer = 0;
    while(temp.length>0) {
        max = Math.max(...temp);
        if(temp[0] !== max) {
            temp.push(temp.shift());
        } else {
            temp.shift();
            answer++;
            if(location===0) return answer;
        }
        location>0 ? location-- : location = temp.length - 1;
    }
}

 

문제

Finn은 요즘 수학공부에 빠져 있습니다. 수학 공부를 하던 Finn은 "자연수 n을 연속한 자연수들로 표현 하는 방법"이 여러개라는 사실을 알게 되었습니다.

예를들어 15는 다음과 같이 4가지로 표현 할 수 있습니다.

1 + 2 + 3 + 4 + 5 = 15

4 + 5 + 6 = 15

7 + 8 = 15

15 = 15

자연수 n이 매개변수로 주어질 때, 연속된 자연수들로 n을 표현하는 방법의 수를 return하는 solution를 완성해주세요.

 

풀이

처음에 찾은 규칙은 약수를 이용하면 될 것 같았다.

15의 약수의 개수 [1,3,5,15] -> 4개

 

14의 약수로 계산해보았을 때 

연속된 경우로 찾을 수 있는 것은 2가지인데,

2+3+4+5 = 14

14 = 14 

약수는 [1,2,7,14] 4개이다. 

 

완전탐색으로 풀어야하나 싶어서 Array.from으로 1부터 n까지 담긴 배열을 만들고, 누적해서 더하다가 15가 되면 카운팅을 한다. 되긴할 것 같은데 시간복잡도에서 별로인 방법이라고 생각했고, 약수를 이용하는 방법을 찾아보기로 했다.

 

해당 문제는

"주어진 수를 연속된 자연수의 합으로 표현하는 방법의 수"와

"주어진 수의 홀수인 약수의 갯수"는 같다.

주어진 수 를 연속된 자연수의 합으로 표현하는 방법 수 = 주어진 수의 약수 중에 홀수의 개수

는 공식을 이용한 풀이라고한다. 

 

약수 중에 홀수인 것의 갯수를 찾아야했다. 

*약수 : 어떤 수를 나누어 나머지 없이 떨어지는 수

15의 약수는 1, 3, 5, 15 이고 이 중 홀수는 4개이다. 

• 약수 1 => 연속하는 1개 자연수의 합으로 표현 가능
   15 = 15
• 약수 3 => 연속하는 3개 자연수의 합으로 표현 가능15를 3으로 나눈값인 5로 표현할 수 있다.
   5 + 5 + 5 = 15 => 3 + 4 + 5 = 15
• 약수 5 => 연속하는 5개 자연수의 합으로 표현 가능15를 5로 나눈값인 3으로 표현할 수 있다.
   3 + 3 + 3 + 3 + 3 = 15 => 1 + 2 + 3 + 4 + 5 = 15
• 약수 15 => 모든 홀수(2n+1)는 n과 n+1로 표현 가능
   7 + 8 = 15

 

 

코드

const solution = (n) => {
  let count = 0;

  for (let i = 0; i <= n; i++) {
    if (n % i === 0 && i % 2 !== 0) {
      count++;
    }
  }

  return count;
}

문제

길이가 같은 배열 A, B

배열 A, B에서 각각 한 개 숫자 뽑아 두 수를 곱한다. -> 배열의 길이만큼 반복. 

두 수를 곱한 값을 누적하여 더한다.

 

최종적으로 누적된 값이 최소가 되도록

(각 배열에서 k번째 숫자 뽑았다면 다음번에 k번째 숫자는 뽑을 수 없다)

 

배열 A, B가 주어질 때 최종저긍로 누적된 최솟값을 return 하는 solution 함수를 완성해주세요.

제한사항

- 배열 A, B의 크기 : 1,000 이하의 자연수

- 배열 A, B의 원소의 크기 : 1,000 이하의 자연수

 

풀이

A에서 가장 작은 값과 B에서 가장 큰 값을 곱하면서 누적하면 최솟값이 만들어진다. 

A를 오름차순 정렬하고, B를 내림차순 정렬한다. 그리고 같은 인덱스 값끼리 곱하면서 누적한 결과값을 리턴한다. 

 

처음에는 어렵게 생각해서 완전탐색으로 풀어야하나 고민했다. 

테스트 케이스로 주어진 2개의 입출력을 보면서 규칙을 보면

배열에서 가장 큰 값부터 순서대로와 가장 작은 값부터 순서대로 곱해서 최솟값을 만들고있었다. (역시 테스트 케이스를 잘 보면서 규칙을 찾아야했다.)

 

코드

const solution = (A, B) => {
  let answer = 0;

  A.sort((a, b) => a - b);
  B.sort((a, b) => b - a);

  for (let i = 0; i < A.length; i++) {
    answer += A[i] * B[i];
  }

  return answer;
}

 

 

문제

주어진 조건에 맞는 n의 다음 큰 숫자를 return 하는 solution 함수를 완성해주세요.

- 조건 1. n의 다음 큰 숫자는 n보다 큰 자연수 입니다.

- 조건 2. n의 다음 큰 숫자와 n은 2진수로 변환했을 때 1의 갯수가 같습니다.

- 조건 3. n의 다음 큰 숫자는 조건 1, 2를 만족하는 수 중 가장 작은 수 입니다.

 

입출력 예

n result
78 83
15 23

 

풀이

n보다 크고, 2진수로 변환했을때 n과 1의 갯수가 같다 -> n과 n보다 큰수를 2진수로 변환한다.

조건 2가지를 만족하는 수 중에서 가장 작은 수

 

2진수로 변환 -> toString() 함수를 사용한다. 

n의 1의 개수를 찾아놓고,

while문으로 n을 하나씩 증가시키면서 다음 큰 수의 2진수의 1의 개수를 찾는다.

비교해서 같으면 멈추고, n을 리턴한다.

 

 

코드

const solution = (n) => {
  let binary = n.toString(2);
  let count = 0;

  // count : n의 이진수에서 1의 개수
  for (let x of binary) {
    if (x === '1') count++;
  }

  while (true) {
    n += 1;
    let bigNumBinary = n.toString(2);
    let bigNumCount = 0;

    // 다음 큰 숫자의 count
    for (let x of bigNumBinary) {
      if (x === '1') bigNumCount++;
    }

    if (count === bigNumCount) break;
  }
  return n;
}

 

문제

문자열 s는 한 개 이상의 단어로 구성되어 있습니다. 각 단어는 하나 이상의 공백문자로 구분되어 있습니다. 각 단어의 짝수번째 알파벳은 대문자로, 홀수번째 알파벳은 소문자로 바꾼 문자열을 리턴하는 함수, solution을 완성하세요.

 

제한 사항

  • 문자열 전체의 짝/홀수 인덱스가 아니라, 단어(공백을 기준)별로 짝/홀수 인덱스를 판단해야합니다.
  • 첫 번째 글자는 0번째 인덱스로 보아 짝수번째 알파벳으로 처리해야 합니다.

 

풀이

문자열의 짝수 인덱스는 대문자로 바꿔주고, 홀수 인덱스는 소문자로 바꿔주는 간단한 문제였다. 

 

꼼꼼하게 짝수 홀수 처리를 해줘야했다. 예시에 있는 테스트 케이스는 통과인데

제출해보면 테스트케이스가 16개중에 4개밖에 통과가 되지않았다.

문제를 꼼꼼하게 읽어야했다. 

try 

hello

world

공백을 기준으로 나눠서 다시 인덱스를 찾아줘야했다. 

 

 

처음 작성한 코드

const solution = (s) => {
  let answer = '';
  let string = s.split('');

  for (let i = 0; i < string.length; i++) {

      if (i % 2 === 0) {
        answer += string[i].toUpperCase();
      } else {
        answer += string[i].toLowerCase();
      }
  }
  return answer;
}

const s = "try hello world";
console.log(solution(s))

 

최종 코드

const solution = (s) => {
  let answer = '';
  let index = 0;

  for (let i = 0; i < s.length; i++) {
    if (s[i] === ' ') {
      index = 0; // 공백이면 인덱스 다시 0으로 초기화
      answer += ' ';
    } else {
      if (index % 2 === 0) {
        answer += s[i].toUpperCase();
      } else {
        answer += s[i].toLowerCase();
      }
      index++; // 공백이 아닐때 인덱스 증가
    }
  }
  return answer;
}

const s = "try hello world";
console.log(solution(s));

 

통과가 안되면 문제를 다시 읽어보자. 

그 전에 문제를 꼼꼼하게 읽자.

+ Recent posts