정보

이 문서는 완성되지 않았습니다. kbotdocs.dev 레포지토리에서 문서에 기여해주세요!

들어가기 전에

이 문서는 자바스크립트를 처음 접하는 초심자를 기준으로 작성되었습니다. 그러므로 카카오톡봇과 자바스크립트를 함께 공부하는 데 도움이 되고자하는 목적을 가집니다. 자바스크립트 또는 다른 프로그래밍 언어를 다루어본 경험이 있을 경우, 문서를 더욱 수월하게 볼 수 있습니다.

알아두기

카카오톡봇 개발 전 꼭 알아두어야 할 몇 가지 사항이 있습니다!

  • Java와 JavaScript는 서로 다른 언어입니다! 이 말은 JavaScript를 "Java"라고 줄여서 부르지 않는다는 것이죠. 차라리 "JS" 라고 부르기로 합시다.
  • 카카오톡봇 개발에 사용되는 JS는 웹 개발에 사용되는 JS가 아니라 Rhino라는 JS구현 엔진입니다. JS의 여러 최신 문법/기능이 빠지긴 했어도 Java클래스를 사용할 수 있다는 장점이 있죠!
  • 카카오톡봇을 작동시키기 위해서는 기기의 운영체제가 Android OS, 그 중에서도 버전 5.0(롤리팝) 이상이어야 해요.

카카오톡봇이 무엇인가요?

카카오톡봇은 카카오톡 상단바 알림을 읽고, 자동으로 응답하는 자동응답 봇이에요. 이걸 개발하기 위해서는 메신저봇R, 채팅 자동응답 봇, StarLight 등의 앱이 쓰인답니다.

개발 준비

정보

이제부터 해당 문서는 메신저봇RAPI2를 기준으로 합니다.

앱 설치

카카오톡봇을 개발하려면, 일단 개발하고 구동시킬 앱이 필요하겠죠? 메신저봇R을 설치하고 봇의 코드를 작성할 파일을 생성해봅시다.

  • 우선, GitHub Release에서 메신저봇R을 설치해주세요.
    • 안드로이드 버전이 7.0(누가) 미만일 경우 Wear OS by Google를 추가로 설치해야 해요. (설치만 하면 된답니다. 이 앱에 대해서는 추가로 설정해야할 것이 없어요!)
  • 메신저봇R 최초 실행 시 데이터 폴더창이 나와요. 앞으로 자신이 개발할 봇의 소스코드를 어디에 저장할 것인지 지정하는 것이니 저장할 폴더를 지정하시면 됩니다.
  • 드디어 메신저봇R의 메인 화면을 구경할 수 있게 되었네요! 자신의 첫 봇을 만들기 위해 우측 하단에 있는 스크립트 추가 버튼을 클릭해봅시다.
  • 새 봇 창에 자신의 봇 이름을 입력하고 확인을 누르세요.
  • 이제 자신의 봇이 어떻게 작동될 것인지를 코딩할 스크립트 파일이 생성되었습니다! 생성된 스크립트를 클릭한 다음 연필 버튼을 클릭하면 소스코드를 작성할 수 있습니다.

부계정을 사용하신다고요?

부계정을 사용할건데 별도로 작업해야할 것이 있냐고요? 음... 모른다는 뜻이 아닙니다.

  • 삼성 듀얼 메신저 기능을 사용하신다면, 봇 전용 계정인 아닌 계정의 카카오톡 알림을 비활성화해야 합니다. 그러지 않으면 봇 전용 계정과 자신의 주 계정 모두가 봇으로서 작동될 수 있어요.
  • 복제 앱을 사용하신다고요? 그러면 메신저봇R > 공용 설정 > 알림을 읽을 패키지명에서 봇으로 사용할 메신저앱의 패키지명을 입력하세요.

기본 스크립트

파일을 생성하고 열어보면 아래와 같이 작성되어있을 거예요.

JS

const bot = BotManager.getCurrentBot();

/**
 * (string) msg.content: 메시지의 내용
 * (string) msg.room: 메시지를 받은 방 이름
 * (User) msg.author: 메시지 전송자
 * (string) msg.author.name: 메시지 전송자 이름
 * (Image) msg.author.avatar: 메시지 전송자 프로필 사진
 * (string) msg.author.avatar.getBase64()
 * (string | null) msg.author.userHash: 사용자의 고유 id
 * (boolean) msg.isGroupChat: 단체/오픈채팅 여부
 * (boolean) msg.isDebugRoom: 디버그룸에서 받은 메시지일 시 true
 * (string) msg.packageName: 메시지를 받은 메신저의 패키지명
 * (void) msg.reply(string): 답장하기
 * (boolean) msg.isMention: 메세지 맨션 포함 여부
 * (bigint) msg.logId: 각 메세지의 고유 id
 * (bigint) msg.channelId: 각 방의 고유 id
 */
function onMessage(msg) {}
bot.addListener(Event.MESSAGE, onMessage);


/**
 * (string) msg.content: 메시지의 내용
 * (string) msg.room: 메시지를 받은 방 이름
 * (User) msg.author: 메시지 전송자
 * (string) msg.author.name: 메시지 전송자 이름
 * (Image) msg.author.avatar: 메시지 전송자 프로필 사진
 * (string) msg.author.avatar.getBase64()
 * (boolean) msg.isDebugRoom: 디버그룸에서 받은 메시지일 시 true
 * (boolean) msg.isGroupChat: 단체/오픈채팅 여부
 * (string) msg.packageName: 메시지를 받은 메신저의 패키지명
 * (void) msg.reply(string): 답장하기
 * (string) msg.command: 명령어 이름
 * (Array) msg.args: 명령어 인자 배열
 */
function onCommand(msg) {}
bot.setCommandPrefix("@"); //@로 시작하는 메시지를 command로 판단
bot.addListener(Event.COMMAND, onCommand);


function onCreate(savedInstanceState, activity) {
    var textView = new android.widget.TextView(activity);
    textView.setText("Hello, World!");
    textView.setTextColor(android.graphics.Color.DKGRAY);
    activity.setContentView(textView);
}

function onStart(activity) {}

function onResume(activity) {}

function onPause(activity) {}

function onStop(activity) {}

function onRestart(activity) {}

function onDestroy(activity) {}

function onBackPressed(activity) {}

bot.addListener(Event.Activity.CREATE, onCreate);
bot.addListener(Event.Activity.START, onStart);
bot.addListener(Event.Activity.RESUME, onResume);
bot.addListener(Event.Activity.PAUSE, onPause);
bot.addListener(Event.Activity.STOP, onStop);
bot.addListener(Event.Activity.RESTART, onRestart);
bot.addListener(Event.Activity.DESTROY, onDestroy);
bot.addListener(Event.Activity.BACK_PRESSED, onBackPressed);

꽤 긴 코드죠? 하지만 기초적인 수준에서 다룰 코드만 남기면 아래와 같아요.

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);

그럼 이제 코드를 하나하나 알아볼까요?

3번째 줄 function onMessage(msg) {}는 카카오톡에서 메시지가 올 때마다 실행돼요. 그러니까 메시지가 올 때마다 실행할 코드는 저 중괄호({}) 사이에 작성할 거예요.

JS

function onMessage(msg) {
    // 메시지가 올 때마다 실행할 코드는 여기에다 작성해요!
}

6번째 줄 function onCommand(msg) {}는 명령어로 판단되는 메시지가 올 때마다 실행돼요. 명령어로 판단되는 메시지가 올 때마다 실행할 코드도 저 중괄호({}) 사이에 작성할 거예요.

JS

function onCommand(msg) {
    // 명령어로 판단되는 메시지가 올 때마다 실행할 코드는 여기에다 작성해요!
}

그런데 명령어로 판단하는 기준은 무엇일까요? 그 기준은 그 다음 줄(7번째 줄)의 코드 bot.setCommandPrefix("@");에서 정해져요. 이 코드의 의미는 무엇일까요?

bot.setCommandPrefix("@");@ 로 시작하는 메시지를 명령어로 판단하라는 의미예요. 그러니까, "안녕?" 과 같은 일반적인 메시지가 아니라 "@help" 와 같은 메시지를 명령어로 인식하게 돼요. 그 말인즉슨, 6번째 줄의 코드는 @ 로 시작하는 메시지가 올 때마다 실행되겠죠?

JS

bot.setCommandPrefix("/");

6번째 코드를 위와 같이 수정하면 / 로 시작하는 메시지를 명령어로 인식하게 돼요. 이제 본격적으로 코드를 작성하며 카카오톡봇과 JS의 기초를 공부해봅시다.

기본 문법

들어가기 전에 JS의 문법을 알아봅시다. 우리가 일상에서 사용하는 한국어의 경우는 문법을 엄격히 지키지 않고 대화해도 의미를 어느정도 파악할 수 있지만, 컴퓨터에게 명령하는 도구인 프로그래밍 언어는 정해진 문법을 제대로 준수하지 않으면 오류를 발생해요. 그래서 올바른 문법을 숙지할 필요가 있어요.

괄호, 따옴표

괄호나 따옴표는 일상에서도 글자들을 묶어내는데 사용하죠. JS에서도 따옴표와 괄호에 관한 문법이 존재해요.

우선, 여는 괄호가 있으면 닫는 괄호도 반드시 와야 해요. 아래의 코드를 보며 자세히 알아볼까요?

JS

msg.reply("안녕하세요!"); // 올바른 문법
msg.reply("안녕하세요!"; // 에러! 닫는 괄호가 존재하지 않아요.
msg.reply"안녕하세요!"); // 에러! 여는 괄호가 존재하지 않아 닫는 괄호가 오면 안돼요.
msg.reply("안녕하세요!); // 에러! 따옴표가 닫히지 않았어요.

1번째 줄의 코드가 올바르게 작성된 코드예요. 여는 괄호와 닫는 괄호, 여는 따옴표와 닫는 따옴표가 올바르게 작성되어 있죠. 반면, 2, 3번째 줄은 괄호가 올바르게 작성되지 않았어요. 4번째 줄은 따옴표를 올바르지 않게 작성했죠.

물론 '여는 괄호, 닫는 괄호를 제대로 준수하는 것은 당연한 것이 아닌가?'라고 생각할 수도 있어요. 하지만 이러한 실수는 프로그래밍 입문자들이 많이 하는 실수 중 하나예요. 그러니 꼭 문법을 꼼꼼히 신경쓰며 작성해야 해요!

세미콜론(;)

세미콜론(;)은 JS뿐만 아니라 다른 많은 프로그래밍 언어에서 중요한 요소예요. 세미콜론은 하나의 코드가 끝났다 라는 의미예요. 우리가 글을 쓸 때 문장 끝에 마침표(.)를 찍는 것과 같죠. JS에서는 코드의 끝에 세미콜론을 쓰는 것을 강제하지는 않아요. 예를 들면,

JS

let num = 23
let str = "hello"
let isChecked = true

이렇게 문장 끝에 세미콜론이 빠져도 코드는 정상적으로 작동해요. 그럼 세미콜론을 붙여야 하는 이유는 무엇일까요?

JS

let num = 23; let str = "hello!"; let isChecked = true;

세미콜론은 코드 하나가 끝났음을 의미하기 때문에 위와 같이 여러 코드를 한줄에 작성해도 컴퓨터는 코드가 3개임을 알 수 있어요. 즉, 정상적으로 작동하죠.

JS

let num = 23 let str = "hello!" let isChecked = true // 에러!

하지만, 세미콜론이 빠지면 위의 코드는 올바르지 않은 문법으로 인식해 에러를 발생해요. let num ...부터 ... isChecked = true까지 통째로 하나의 코드로 인식하는데, 이런 코드는 JS에 존재하지 않는 문법이거든요! 그래서 되도록이면 코드의 끝마다 세미콜론을 붙이는 걸 권장해요.

변수와 자료형

프로그래밍에서 가장 빈번하게 하는 일 중 하나는 데이터를 다루는 일이예요. 또한, 데이터에는 여러 타입이 존재하죠. 우선 자료형(데이터 타입)에 대해 알아볼까요?

JS에는 여러 자료형이 존재해요. 그 중 살펴볼 것은 숫자, 문자열, 부울(Boolean) 이예요.

JS

123 // 숫자형
"123" // 문자열
"hello!" // 문자열
'Hi, Kakaotalk Bot!' // 문자열
true // 부울형
false // 부울형
"true" // 문자열

숫자형은 0~9까지의 아라비아 숫자로 나타내요. 숫자형끼리는 연산이 가능한데, 예를 들어 12 + 3547 이라는 값을 나타내요.

문자열은 1개 이상의 문자들을 다루는데 사용돼요. 문자열은 큰따옴표(" ") 또는 작은따옴표(' ') 사이에 값을 입력해요. 이 점이 중요한데, 큰따옴표나 작은따옴표로 감싸지 않은 123은 숫자형으로 취급하지만, "123" 또는 '123'은 문자열로 취급해요. 그래서 "12" + "35""1235"라는 값을 의미하게 되죠. + 연산을 하는 두 값 중 적어도 하나가 문자열이면 + 연산은 두 값을 연결해서 나타내요. 이건 예제를 보며 이해하는게 더 편할 거예요.

JS

2 + 54 // 56 (숫자형)
"2" + 54 // "254" (문자열)
"2" + "54" // "254" (문자열)
"This is " + true // "This is true" (문자열)

부울형(Boolean)은 참과 거짓을 나타낼 때 사용해요. 부울형이 되는 값은 참을 나타내는 true, 거짓을 나타내는 false 두 개가 있어요. 하지만 숫자형과 문자열도 부울형으로 나타낼 수 있어요.

숫자형 데이터의 경우, 기본적으로 true로 나타나지만, 0false로 나타나요. 문자열 데이터의 경우 또한 기본적으로 true로 나타나지만 ""(빈 문자열)의 경우 false로 나타나요.

이제 데이터를 저장하는 그릇인 변수에 대해 알아볼까요? JS에서 변수는 let이라는 예약어를 이용해서 선언해요.

JS

let apple;
let Apple;

위 코드는 각각 apple, Apple이란 이름을 가지는 변수를 선언해요. 두 개는 똑같은 게 아니냐고요? 프로그래밍에선 대소문자를 엄격하게 구분하기 때문에 두 변수는 엄연히 다른 변수예요.

변수의 이름은 프로그래머가 원하는 것으로 지을 수 있지만, 몇 가지 규칙이 존재해요.

  • 변수 이름의 첫 글자는 영문자, 달러기호($), 언더바(_)만 올 수 있어요. 가령, let 10min;과 같이 작성하면 에러가 발생해요.
  • 변수 이름의 두번째 글자부터는 영문자, 숫자, 달러기호($), 언더바(_)만 올 수 있어요. 그러니까, let log_2_10;과 같이 작성해도 정상작동해요.
  • JS에서 이미 사용 중인 예약어(let, if, for 등)는 변수 이름으로 지을 수 없어요.

변수에 값을 저장하는 것을 할당이라고 하는데, 그러면 할당은 어떻게 하는 걸까요? 할당은 = 연산자를 이용해요.

JS

let num; // 비어있음(undefined)
num = 31; // 변수 num에 숫자형 값 31을 할당

1번째 줄의 let num;num이란 변수를 선언하지만 값이 할당되지 않은, 비어있는 상태로 존재해요. 2번째 줄의 num = 31;은 비어있는 num변수에 숫자형 값 31을 할당해요. 사실, 이와 같은 과정을 더 간단히 할 수 있는데,

JS

let num = 31; // 변수 num을 선언함과 동시에 숫자형 값 31을 할당

위 코드와 같이 선언과 할당을 동시에 할 수 있어요. 만약 num의 값을 54로 변경(재할당)하고 싶으면 num = 54;와 같이 작성하면 되겠죠? JS는 타입의 구분이 다른 언어보다 엄격하지 않아서, num = "Hello!";처럼 다른 데이터 타입의 값으로 변경할 수도 있어요.

만약, 값이 바뀌지 않는 상수를 선언하고 싶으면, let 대신 const 키워드를 사용하세요! 대신, 상수는 반드시 선언과 할당을 동시에 해야 합니다!

JS

const PI = 3.141592;
PI = 2.713; // 에러! 상수는 재할당을 할 수 없어요.
const OpenMsg; // 에러! 꼭 선언과 할당을 동시에 해야 해요.

연산자

연산자는 무엇일까요? '연산자'라고 하면 수학의 더하기(+), 빼기(-), 곱하기(×), 나누기(÷) 등 값을 계산하는 사칙연산자가 먼저 떠오를 수 있어요. 프로그래밍에서는 이러한 사칙연산 뿐만 아니라 다른 다양한 연산을 위한 연산자를 제공해요.
연산자의 종류는 매우 다양해요. 그러니까 연산자들을 모조리 암기하려고 하시진 마셨으면 좋겠어요. 이 장에서 연산자를 소개하는 이유는 여러분에게 연산자 외우기 숙제를 주려는 것이 아니라 앞으로 이를 많이 쓰게 될 것이란 의미니까요! 프로그래밍을 하다 보면 자연스럽게 익힐 수 있으니 걱정 마세요.

산술 연산자

산술 연산자는 방금 예시로 든 사칙연산과 같은 연산을 할 수 있도록 해요. 덧셈, 뺄셈 등과 같은 계산을 할 수 있도록 하죠.

여러가지 산술 연산자
더하기 +

두 피연산자를 더했을 때의 값을 반환합니다.

JS

12 + 5; // 17
빼기 -

두 피연산자를 뺐을 때의 값을 반환합니다.

JS

12 - 5; // 7
곱하기 *

두 피연산자를 곱했을 때의 값을 반환합니다.

JS

12 * 5; // 60
나누기 /

두 피연산자를 나눴을 때의 값을 반환합니다.

JS

12 / 5; // 2.4
나머지 %

두 피연산자를 나눴을 때 나머지가 되는 값을 반환합니다.

JS

12 % 5; // 2
거듭제곱 **

두 피연산자에 대하여 거듭제곱했을 때의 값을 반환합니다. 가령, A ** B의 경우 ABA^{B}의 값을 반환합니다.

JS

2 ** 4; // 16
증가 ++

피연산자에 1을 더합니다. 증가 연산자는 ++x 또는 x++로 사용할 수 있으나, 두 방법은 동작 방식이 다릅니다.

++xx의 값을 1 더한 다음 x의 값을 반환합니다.

JS

let x = 3; // x의 초기값: 3
msg.reply(++x); // x에 1을 더한 다음 값을 반환하므로 4를 출력합니다.

반면, x++x의 값을 반환한 다음 x의 값을 1 더합니다.

JS

let x = 3; // x의 초기값: 3
msg.reply(x++); // x의 값을 먼저 반환하므로 3을 출력합니다. ... 이제 x에 1을 더했습니다!
msg.reply(x); // 4를 반환합니다.
감소 --

피연산자에 1을 뺍니다. 감소 연산자는 증가 연산자와 마찬가지로 --x 또는 x--로 사용할 수 있으나, 두 방법은 동작 방식이 다릅니다.

--xx의 값을 1 뺀 다음 x의 값을 반환합니다.

JS

let x = 3; // x의 초기값: 3
msg.reply(--x); // x에 1을 뺀 다음 값을 반환하므로 2를 출력합니다.

반면, x--x의 값을 반환한 다음 x의 값을 1 뺍니다.

JS

let x = 3; // x의 초기값: 3
msg.reply(x--); // x의 값을 먼저 반환하므로 3을 출력합니다. ... 이제 x에 1을 뺐습니다!
msg.reply(x); // 2를 반환합니다.
단항부정 -

피연산자의 부호를 반대로 바꾼 값을 반환합니다.

JS

let x = 3;
let y = -5;
-x; // -3
-y; // 5
단항플러스 +

피연산자가 숫자형이 아니면 숫자형으로의 변환을 시도합니다. 숫자형으로의 변환을 실패할 경우, NaN(Not a Number)을 반환합니다.

JS

+"3" // 3
+true // 1
+"string" // NaN

비교 연산자

비교 연산자는 두 값을 비교하고 비교 결과에 따른 부울 값을 반환해요. '두 값이 같은가?', '다른가?', '더 큰가?' 와 같은 의미를 지녀요.

여러가지 비교 연산자
동등 ==

두 피연산자의 값이 같으면 true를, 아니면 false를 반환합니다.

JS

const n1 = 3;
const n2 = 5;
n1 == 3; // true
n1 == n2; // false
n1 == "3"; // true
부등 !=

두 피연산자의 값이 다르면 true를, 아니면 false를 반환합니다.

JS

const n1 = 3;
const n2 = 5;
n1 != 3; // false
n1 != n2; // true
n1 != "3"; // false
일치 ===

두 피연산자의 값과 자료형 모두 같으면 true를, 아니면 false를 반환합니다.

JS

const n1 = 3;
const n2 = 5;
n1 === 3; // true
n1 === n2; // false
n1 === "3"; // false
불일치 !==

두 피연산자의 값 또는 자료형이 다르면 true를, 아니면 false를 반환합니다.

JS

const n1 = 3;
const n2 = 5;
n1 === 3; // false
n1 === n2; // true
n1 === "3"; // true
>

왼쪽 피연산자의 값이 오른쪽 피연산자의 값보다 크면 true를, 아니면 false를 반환합니다.

JS

const n1 = 3;
const n2 = 5;
n1 > 1; // true
n1 > n2; // false
n1 > 3; // false
크거나 같음 >=

왼쪽 피연산자의 값이 오른쪽 피연산자의 값보다 크거나 같으면 true를, 아니면 false를 반환합니다.

JS

const n1 = 3;
const n2 = 5;
n1 >= 1; // true
n1 >= n2; // false
n1 >= 3; // true
작음 <

왼쪽 피연산자의 값이 오른쪽 피연산자의 값보다 작으면 true를, 아니면 false를 반환합니다.

JS

const n1 = 3;
const n2 = 5;
n2 < 7; // true
n2 < n1; // false
n2 < 5; // false
작거나 같음 <=

왼쪽 피연산자의 값이 오른쪽 피연산자의 값보다 작거나 같으면 true를, 아니면 false를 반환합니다.

JS

const n1 = 3;
const n2 = 5;
n2 <= 7; // true
n2 <= n1; // false
n2 <= 5; // true

정보

무엇이든 적절한 때에 적절한 연산자를 사용하는 것이 좋지만, 그 외의 상황에서는 두 값의 일치/불일치를 판단할 때 동등 연산자(==)보다 일치 연산자(===)를 사용하는 것을 권장합니다. 일치 연산자는 값 뿐만 아니라 자료형까지 고려하기 때문에 더 엄밀한 비교가 가능하기 때문입니다. 가령, 다음과 같은 상황을 생각해봅시다.


JS

if (x == 3) { // x의 값이 3일 경우
    x = x + 2; // x에 2를 더합니다! ..라고 생각하셨겠죠?
}

아마도 여러분들은 위 코드를 보고 x의 값이 3일 경우 x의 값은 5가 되리라 기대할 겁니다. 하지만 이 코드는 여러분들이 예상하지 못한 결과를 낳을 수도 있습니다.


JS

if (x == 3) { // x가 문자열 "3"일 경우에도 참입니다.
    x = x + 2; // 따라서 이 경우엔 x의 값은 5가 아니라 문자열 "32"가 됩니다!
}

JS는 다른 프로그래밍 언어에 비해 자료형에 대해 관대하지만, 이는 여러분이 예상하지 못한 결과로 빠질 가능성이 상대적으로 높다는 것을 의미하기도 합니다. 그렇기에 자료형까지 비교하는 동등 연산자를 권장하는 것이죠! 마찬가지의 이유로 부등 연산자(!=) 또한 불일치 연산자(!==)를 대신 사용하기를 권장합니다.

할당 연산자

할당 연산자는 왼쪽 피연산자에 오른쪽 피연산자의 값을 할당해요. 우리가 이전에 알아본 변수에서도 =를 이용해 값을 할당했었죠? = 또한 할당 연산자 중 하나예요. 이 외에도 여러 할당 연산자가 있으니 알아보도록 해요!

여러가지 할당 연산자
할당 =

왼쪽 피연산자에 오른쪽 피연산자의 값을 할당합니다.

JS

let x = 12; // x에 12를 할당합니다. x의 값은 12입니다.
x = 5; // x에 5를 다시 할당합니다. 이제 x의 값은 5입니다!
더하기 할당 +=

기존 왼쪽 피연산자의 값에 오른쪽 피연산자의 값을 더한 값을 왼쪽 피연산자에 할당합니다.
... 말이 조금 어렵죠? 그러니까, A += BA = A + B와 같아요.

JS

let x = 12; // x에 12를 할당합니다. x의 값은 12입니다.
x += 5; // x의 값(12)과 5를 더한 값을 할당합니다. 이제 x의 값은 17입니다!
빼기 할당 -=

기존 왼쪽 피연산자의 값에 오른쪽 피연산자의 값을 뺀 값을 왼쪽 피연산자에 할당합니다. 가령, A -= BA = A - B와 같습니다.

JS

let x = 12; // x에 12를 할당합니다. x의 값은 12입니다.
x -= 5; // x의 값(12)에 5를 뺀 값을 할당합니다. 이제 x의 값은 7입니다!
곱하기 할당 *=

기존 왼쪽 피연산자의 값에 오른쪽 피연산자의 값을 곱한 값을 왼쪽 피연산자에 할당합니다. 가령, A *= BA = A * B와 같습니다.

JS

let x = 12; // x에 12를 할당합니다. x의 값은 12입니다.
x *= 5; // x의 값(12)에 5를 곱한 값을 할당합니다. 이제 x의 값은 60입니다!
나누기 할당 /=

기존 왼쪽 피연산자의 값에 오른쪽 피연산자의 값을 나눈 값을 왼쪽 피연산자에 할당합니다. 가령, A /= BA = A / B와 같습니다.

JS

let x = 12; // x에 12를 할당합니다. x의 값은 12입니다.
x /= 5; // x의 값(12)에 5를 나눈 값을 할당합니다. 이제 x의 값은 2.4입니다!
나머지 할당 %=

기존 왼쪽 피연산자의 값에 오른쪽 피연산자의 값을 나눴을 때 나머지가 되는 값을 왼쪽 피연산자에 할당합니다. 가령, A %= BA = A % B와 같습니다.

JS

let x = 12; // x에 12를 할당합니다. x의 값은 12입니다.
x %= 5; // x의 값(12)에 5를 나눴을 때 나머지가 되는 값을 할당합니다. 이제 x의 값은 2입니다!
거듭제곱 할당 **=

기존 왼쪽 피연산자의 값에 오른쪽 피연산자의 값만큼 거듭제곱한 값을 왼쪽 피연산자에 할당합니다. 가령, A **= BA = A ** B와 같습니다.

JS

let x = 2; // x에 2를 할당합니다. x의 값은 2입니다.
x **= 4; // x의 값(2)에 5를 거듭제곱한 값을 할당합니다. 이제 x의 값은 16입니다!

논리 연산자

논리 연산자는 '그리고', '또는', '아니다'를 연산으로 제공하며, 피연산자들의 부울(Boolean)값을 이용해요. 논리 연산자는 개수가 적지만, 이를 잘 활용하면 더 좋은 코드를 작성할 수 있어요.

여러가지 논리 연산자
논리AND &&

A && B에서, A의 값을 false로 볼 수 있으면 A를 반환하며, 그렇지 않으면 B를 반환합니다.
부울 값과 사용했을 때 AB 모두 true이면 true를, 그렇지 않으면 false를 반환합니다.

JS

0 && 1; // 0 (0은 false로 볼 수 있습니다.)
1 && 2; // 1 (1은 0이 아니므로 true로 볼 수 있습니다.)
3 && ""; // "" (빈 문자열 ""는 false로 볼 수 있습니다.)
논리OR ||

A || B에서, A의 값을 true로 볼 수 있으면 A를 반환하며, 그렇지 않으면 B를 반환합니다.
부울 값과 사용했을 때 AB 둘 중 적어도 하나가 true이면 true를, 그렇지 않으면 false를 반환합니다.

JS

0 || 1; // 1 (1은 true로 볼 수 있습니다.)
1 || 2; // 1 (1은 true로 볼 수 있습니다.)
3 || ""; // 3 (3은 true로 볼 수 있습니다.)

정보

기호 |는 수직선(Vertical line), 바(Bar) 등으로 불리는 기호예요. shift+\(원화 기호 키로 보임)을 눌러 입력할 수 있어요.

논리NOT !

!A에서, A의 값을 true로 볼 수 있으면 false를 반환하며, 그렇지 않으면 true를 반환합니다. 즉, 피연산자의 값에 대한 부울 값을 부정한 값을 반환합니다.

JS

!true // false
!0 // true
!(23 > 10) // false

메시지 보내기

카카오톡봇의 기본 기능은 메시지를 보내는 것이죠. 이제부터 메시지를 보내는 것에 대해 알아볼 거예요. 카카오톡봇에서 메시지를 보낼 때는 msg.reply()를 이용해요. 괄호 안에 보낼 메시지를 입력하면 돼요.

주의

아래의 예제 소스는 채팅을 방해하는 등 피해를 줄 수 있으므로 실제 채팅방에는 적용하지 않는 것을 권장합니다. 메신저봇 앱 내 디버깅룸에서만 테스트하세요.

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {
    msg.reply("안녕하세요");
}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);

위와 같이 function onMessage(msg) {} 의 중괄호 사이에 msg.reply("안녕하세요");를 작성해요. function onMessage(msg) {}는 메시지가 올 때마다 코드를 실행한다고 했죠? 그래서 이 코드는 메시지가 올 때마다 안녕하세요 라는 메시지를 보내요.

조건문과 메시지 보내기

아까의 예제는 실제 채팅방에서 구동하면 사람들이 메시지를 보낼 때마다 채팅을 보내기 때문에 피해를 줄 수 있어요. 그래서 특정 메시지가 수신되었을 때만 메시지를 보내는 방법을 알아볼 필요가 있어요. 이러한 기능은 JS의 조건문을 이용할 거예요.

조건문은 if, else if, else 3가지 키워드를 이용해요. 우선 기본적인 조건문부터 살펴볼게요.

하나의 케이스: if문

조건문의 기본 키워드는 if예요. if 키워드는 특정 조건을 만족할 때에만 코드를 실행하는데 사용해요. 아래의 예제를 볼까요?

JS

if (condition) { // condition이 true이면
    // 중괄호 내부의 코드를 실행
}

if문은 condition의 값이 true이면 중괄호 내부의 코드들을 실행해요. 만약 condition 자리에 10 > 2(102보다 크다. 즉, true)이 들어가면 if문 내의 코드가 실행될 거예요. 반면, condition 자리에 32 < 4(324보다 작다. 즉, false)이 들어가면 if문 내의 코드를 실행하지 않아요.

이제 이를 이용해 특정 메시지에만 반응하는 소스코드를 작성해볼까요?

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {
    if (msg.content === "안녕") { // 메시지 내용이 '안녕' 이면
        msg.reply("안녕하세요!"); // '안녕하세요!' 라고 메시지 수신
    }
}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);

onMessage 함수 내의 코드를 수정했어요. 위 코드를 차근차근 살펴볼까요?

msg.content는 사용자가 보낸 메시지의 내용이예요. 사용자가 '안녕' 이라는 메시지를 보내면 msg.content안녕 이라는 문자열 값을 가지게 되죠.

===일치 연산자라는 연산자예요. A === B 라는 코드는 AB가 같은 값을 가지는지를 검사하죠. 만약 두 값이 같으면 true를, 같지 않으면 false를 반환해요. 즉, msg.content === "안녕"은, 사용자가 보낸 메시지의 내용이 '안녕'인가? 를 의미해요.

사용자가 보낸 메시지가 '안녕'이면 msg.content === "안녕"true가 되겠죠? 그러므로 카카오톡봇은 '안녕하세요!' 라는 메시지를 보내게 될 거예요.

주의

이 편의 예제 소스는 채팅을 방해하는 등 피해를 줄 수 있으므로 실제 채팅방에는 적용하지 않는 것을 권장합니다. 메신저봇 앱 내 디버깅룸에서만 테스트하세요.

if-else문

else 키워드는 주어진 조건이 거짓일 경우의 행동을 작성하기 위해 사용돼요. 일단 예제를 통해 천천히 이해해볼까요?

사용자가 보낸 메시지가 '안녕'이면 '안녕하세요!'라고 답장하고 사용자가 보낸 메시지가 '안녕'이 아니면 '메시지가 감지되었어요.'라고 답장하는 코드를 한번 작성해볼꺼예요.
논리NOT 연산자(!) 또는 불일치 연산자(!==)를 이용해 아래와 같이 작성할 수 있어요.

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {
    if (msg.content === "안녕") { // 메시지 내용이 '안녕' 이면
        msg.reply("안녕하세요!"); // '안녕하세요!' 라고 메시지 수신
    }
    if (!(msg.content === "안녕")) { // 메시지 내용이 '안녕'이 아니면
        msg.reply("메시지가 감지되었어요."); // '메시지가 감지되었어요.' 라고 메시지 수신
    }
}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {
    if (msg.content === "안녕") { // 메시지 내용이 '안녕' 이면
        msg.reply("안녕하세요!"); // '안녕하세요!' 라고 메시지 수신
    }
    if (msg.content !== "안녕") { // 메시지 내용이 '안녕'이 아니면
        msg.reply("메시지가 감지되었어요."); // '메시지가 감지되었어요.' 라고 메시지 수신
    }
}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);

하지만 비슷한 식을 여러 번 쓰니 조금 복잡하죠? 게다가 조건이 달라지면 하나하나 수정해야 하기 때문에 코드를 관리하거나 수정할 때도 불편할 거예요. 그래서 이러한 상황에선 else 키워드가 유용할 수 있어요.

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {
    if (msg.content === "안녕") { // 메시지 내용이 '안녕' 이면
        msg.reply("안녕하세요!"); // '안녕하세요!' 라고 메시지 수신
    }
    else { // 메시지 내용이 '안녕'이 아니면
        msg.reply("메시지가 감지되었어요."); // '메시지가 감지되었어요.' 라고 메시지 수신
    }
}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);

if문에 작성된 조건이 참일 경우 if의 중괄호 내의 코드들을 실행하고, 조건이 거짓일 경우 else의 중괄호 내의 코드들을 실행해요. else 키워드는 반드시 if로 시작하는 조건문의 맨 마지막에 붙어야 해요. if문에 제시된 조건이 아닐 경우를 고려하기 위한 키워드니까요!

여러 케이스: else if문

하나의 메시지에만 대응하는 카카오톡봇을 만들지는 않을 거잖아요? 예를 들면, '안녕'이라는 메시지에는 '안녕하세요!'라고 답장하고, '너는 누구니?'라는 메시지에는 '저는 카카오톡봇이예요.'라고 답장하는 코드를 작성해볼꺼예요.

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {
    if (msg.content === "안녕") { // 메시지 내용이 '안녕' 이면
        msg.reply("안녕하세요!"); // '안녕하세요!' 라고 메시지 수신
    }
    else if (msg.content === "너는 누구니?") { // 메시지 내용이 '너는 누구니?' 이면
        msg.reply("저는 카카오톡봇이예요."); // '저는 카카오톡봇이예요.' 라고 메시지 수신
    }
}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);

else if 키워드는 맨 처음 if에서 제시된 조건이 거짓일 때, 추가로 조건을 검사하기 위해 사용해요. 저 예제를 이용해 설명하자면, if (msg.content === "안녕") {...}에서 제시된 조건 msg.content === "안녕"이 거짓일 경우 else if (msg.content === "너는 누구니?") {...}에서 제시된 조건 msg.content === "너는 누구니?"를 검사해요. 사용자가 보낸 메시지가 '안녕'도 아니고, '너는 누구니?'도 아니면 카카오톡봇은 아무런 행동도 하지 않겠죠?

더 많은 케이스에 대응하고 싶으면 아래와 같이 else if를 여러 개 사용하면 돼요.

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {
    if (msg.content === "메시지1") {
        msg.reply("답장1");
    }
    else if (msg.content === "메시지2") {
        msg.reply("답장2");
    }
    else if (msg.content === "메시지3") {
        msg.reply("답장3");
    }
    else if (msg.content === "메시지4") {
        msg.reply("답장4");
    }
    // ...
}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);

else if문은 if로 시작하는 조건문 다음에 붙을 수 있어요. 또한, else보다 먼저 등장해야해요. 지금까지 알아본 조건문을 정리해보면 아래와 같아요.

JS

if (condition1) {
    // toDo: condition1이 true일 때의 코드
}
else if (condition2) {
    // toDo: condition1은 false, condition2은 true일 때의 코드
}
else if (condition3) {
    // toDo: condition1, condition2는 false, condition3은 true일 때의 코드
}
// ...
else if (conditionN) {
    // toDo: condition1, condition2, ..., condition(N-1)은 false, conditionN은 true일 때의 코드
}
else {
    // toDo: condition1부터 conditionN까지 모두 false일 때의 코드
}

명령어와 접두어

API2에서 명령어(command)는 특정 접두어로 시작하는 메시지예요. 예를 들면, 접두어를 '/'로 정했을 경우 '/help', '/time' 등과 같은 메시지를 명령어로 봐요. 기본 스크립트 편에서 알아본 내용 기억하시나요?

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);

여기에서 bot.setCommandPrefix()접두어를 정하는 함수, function onCommand(msg) {}는 설정한 접두어로 시작하는 메시지, 즉 명령어를 감지했을 때 실행할 함수예요. 위 코드의 경우, 접두어가 '@'로 정해져있으니 function onCommand(msg) {}는 '@help', '@time'과 같은 메시지가 올 때마다 실행될 함수가 되는 것이죠.

onCommand(msg)msg에는 명령어를 처리하는데 더 편리한 값들을 제공해요. 그것들을 잠깐 알아볼게요.

msg 의 몇몇 유용한 프로퍼티
msg.command

명령어의 이름입니다.

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {
    /*
    msg.content === "@help"일 경우: 'help' 출력
    msg.content === "@translate en ko apple"일 경우: 'translate' 출력
    */
    msg.reply(msg.command);
}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);
msg.args

명령어의 인자들을 모은 배열입니다.

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {
    /*
    msg.content === "@help"일 경우: '' 출력
    msg.content === "@translate en ko apple"일 경우: 'en, ko, apple' 출력
    */
    msg.reply(msg.args);
}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);

그럼 이제 여러 명령어들에 대한 처리를 해볼까요? 이전에 알아본 조건문을 이용해 코드를 작성할 수 있어요.

JS

const bot = BotManager.getCurrentBot();

function onMessage(msg) {}
bot.addListener(Event.MESSAGE, onMessage);

function onCommand(msg) {
    if (msg.command === "help") { // '@help' 명령어 처리
        msg.reply("명령어 목록입니다. \n\n- @help: 명령어 목록을 출력합니다. \n- @time: 현재 시간을 출력합니다.");
    }
    else if (msg.command === "time") { // '@time' 명령어 처리
        let date = new Date();
        msg.reply(`현재 시간은 ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()} 입니다.`);
    }
}
bot.setCommandPrefix("@");
bot.addListener(Event.COMMAND, onCommand);