: 원래의 자리로 되돌아가거나 되돌아옴
function recursion () {
console.log("This is")
console.log("recursion!")
recursion()
}
// `recursion` 함수를 호출하면 무한 루프 발생
=> 재귀 함수는 recursion
함수 처럼 자기 자신을 호출하는 함수를 의미한다.
문제를 작게 쪼개기 (문제를 동일한 방식으로 계속 쪼개기)
=> 쪼개는 방식이 recursive case
문제를 가장 작은 단위로 쪼개기 (더 이상 안 쪼개지면 그것이 base case)
=> 재귀 함수의 탈출 조건
문제 해결하기 (base case 해결하기)
=> 쪼개졌던 문제가 한 번에 해결된다.
arrSum
함수 작성1) 문제를 작게 쪼개기 적용
/* 배열의 합을 구할 때 [1, 2, 3]의 합을 구하는 것보다
[2, 3]의 합을 구하는 것이 더 작은 문제 ... */
arrSum([1,2,3]) === 1 + arrSum([2,3])
arrSum([2,3]) === 2 + arrSum([3])
...
2) 문제를 가장 작은 단위로 쪼개기
// 위에서 문제를 쪼갠 방식을 반복해서 문제를 쪼개면 더이상 쪼갤 수 없는 상태 도달
arrSum([1,2,3]) === 1 + arrSum([2,3])
arrSum([2,3]) === 2 + arrSum([3])
arrSum([3]) === 3 + arrSum([])
3) 문제 해결하기
/* 문제를 쪼갤 때 같은 방식으로 쪼갰기 때문에
가장 작은 단위의 문제를 해결한 방식으로 문제 전체를 해결 가능 */
arrSum([]) === 0 // 문제가 더는 작아지지 않는 순간
arrSum([3]) === 3 + arrSum([]) === 3 + 0 === 3
arrSum([2,3]) === 2 + arrSum([3]) === 2 + 3 === 5
arrSum([1,2,3]) === 1 + arrSum([2,3]) === 1 + 5 === 6
arrSum
작성function arrSum (arr) {
// 빈 배열을 입력 받았을 때 0을 리턴하는 조건문
// 가장 작은 문제를 해결하는 코드, 재귀를 멈추는 코드
if(arr.length === 0) {
return 0
}
// 배열의 첫 요소 + 나머지 요소가 담긴 배열을 받는 arrSum 함수
// 재귀(자기 자신 호출)를 통해 문제를 작게 쪼개나가는 코드
return arr.shift() + arrSum(arr)
=> 모든 재귀 함수는 반복문으로 표현 가능하지만 재귀를 적용한 코드가 더욱 간결하고 이해하기 쉽다.
재귀적 사고를 위해 가장 먼저 해야 할 일 : 문제를 추상적으로, 단순하게 정의하는 것
arrSum
의 경우 number
타입을 요소로 갖는 배열을 입력으로 받고, number
타입 리턴arrSum: [number] => number
입출력값 정의문제를 쪼갤 기준을 정하고, 주어진 입력값에 따라 경우의 수를 나눠서
문제를 더 이상 쪼갤 수 없는 경우와 그렇지 않은 경우로 나눈다.
arrSum
은 입력값이 빈 배열인 경우와 그렇지 않은 경우로 나눌 수 있다.arrSum: [number] => number
arrSum([ ])
입력값이 빈 배열인 경우arrSum([요소1, 요소2, ... , 요소n])
그렇지 않은 경우문제를 여러 경우로 구분한 다음, 가장 해결하기 쉬운 문제부터 해결 => 재귀의 기초(base case)
재귀의 기초(base case) : 재귀 함수를 구현할 때, 재귀의 탈출 조건(재귀 호출이 멈추는 조건)을 구성
( 탈출 조건이 없는 경우, 재귀 함수는 끝없이 자기 자신을 호출한다. 문제를 최대한 작게 쪼갠 후 문제 해결하는 것이 중요하다.)
arrSum
을 더 이상 쪼갤 수 없는 경우는 입력값이 빈 배열일 경우이고, 이때 arrSum([])
의 리턴값은 0이다.arrSum: [number] => number
arrSum([ ]) === 0
입력값이 빈 배열인 경우 : "해결"arrSum([요소1, 요소2, ... , 요소n])
arrSum
에 입력된 경우,arrSum: [number] => number
arrSum([ ]) === 0
arrSum([요소1, 요소2, ... , 요소n])
그렇지 않은 경우 : "해결"arrSum
을 재귀적으로 구현 가능function arrSum(arr) {
// base case : 문제를 더 이상 쪼갤 수 없는 경우 (재귀의 기초)
if (arr의 길이가 0인 경우) {
return 0;
}
// recursive case : 그렇지 않은 경우
return 요소1 + arrSum([요소2, ... , 요소n]);
}
function recursive (input1, input2, ...) {
// base case : 문제를 더 이상 쪼갤 수 없는 경우
if (문제를 더 이상 쪼갤 수 없는 경우) {
return 단순한 문제의 해답;
}
//recursive case : 그렇지 않은 경우
return 더 작은 문제로 새롭게 정의된 문제
}
: 서로 다른 프로그램 사이에서 데이터 교환을 위해 만들어진 객체 형태의 포맷
전송 가능한 조건 (transferable condition)
객체는 타입 변환을 이용해 String으로 변환할 경우 객체 내용을 포함하지 않는다.
- JavaScript에서 message.toString()
또는 String(message)
을 시도하면 [object Object]
라는 결과를 리턴한다.
위 문제를 해결하는 방법
=> 객체를 JSON의 형태로 변환하거나 JSON을 객체의 형태로 변환
JSON.stringify
: 객체를 JSON으로 변환 => 직렬화(serialize)
JSON.parse
: JSON을 객체로 변환 => 역직렬화(deserialize)
// 메시지를 담고 있는 객체
const message = {
sender: "김코딩",
receiver: "박해커",
message: "안녕?",
createdAt: "2022-10-22 10:10:10"
}
let transMessage = JSON.stringify(message)
console.log(transMessage)
// `{"sender":"김코딩","receiver":"박해커","message":"안녕?","createdAt":"2022-10-22 10:10:10"}`
console.log(typeof(transMessage))
// `string`
=> message 객체를 JSON으로 변환하는 메서드 JSON.stringify
let packet = `{"sender":"김코딩","receiver":"박해커","message":"안녕?","createdAt":"2022-10-22 10:10:10"}`
let obj = JSON.parse(packet)
console.log(obj)
/*
{
sender: "김코딩",
receiver: "박해커",
message: "안녕?",
createdAt: "2022-10-22 10:10:10"
}
*/
console.log(typeof(obj))
// `object`
직렬화된 JSON에 메서드 JSON.parse를 적용하면 다시 객체의 형태로 변환할 수 있다.
JavaScript의 객체와 같은 규칙을 가지지 않는다.