자바스크립트 기초 - 4
목차
1. alert, prompt, confirm을 이용한 상호작용
2. 조건부 연산자 if와 ?
3. 논리 연산자
1. alert, prompt, confirm
현재 브라우저를 데모 환경으로 사용 중이므로 브라우저 환경에서 사용되는 최소한의 사용자 인터페이스 기능에 대해서 알아 둘 필요가 있습니다. 이 챕터에서는 브라우저가 제공해 주는 함수인 alert, prompt, confirm에 대해 알아보겠습니다.
1.1 alert
얼럿(alert) 창은 메시지를 보여주는 창입니다. 사용자가 얼럿 창의 “확인(OK)” 버튼을 누를 때까지 메시지는 계속 떠 있고, 스크립트의 실행이 일시적으로 중단됩니다.
alert("message");
메시지가 있는 작은 창은 모달 창(modal window) 이라고 부릅니다. “모달”이란 단어엔 페이지의 나머지 부분과 상호 작용이 불가능하다는 의미가 내포되어 있습니다. 따라서 사용자는 모달 창 바깥에 있는 버튼을 누른다든가 하는 행동을 할 수 없습니다. 확인 버튼을 누르기 전까지 말이죠.
1.2 prompt
브라우저에서 제공하는 prompt 함수는 두 개의 인수를 받습니다.
result = prompt(title, [default]);
이 함수는 텍스트 메시지와 입력 필드(input field), 확인(OK) 및 취소(Cancel) 버튼이 있는 모달 창을 띄워줍니다.
title
사용자에게 보여줄 문자열.
default
입력 필드의 초깃값(선택사항).
사용자는 프롬프트 대화상자의 입력 필드에 원하는 값을 입력하고 확인을 누를 수 있습니다. 값을 입력하길 원하지 않는 경우는 취소(Cancel) 버튼을 누르거나 Esc를 눌러 대화상자를 빠져나갈 수 있습니다.
prompt 함수는 사용자가 입력 필드에 기재한 문자열을 반환합니다. 사용자가 입력을 취소한 경우는 null이 반환됩니다.
let age = prompt('나이를 입력해주세요.', 100);
alert(`당신의 나이는 ${age}살 입니다.`); // 당신의 나이는 100살입니다.
Internet Explorer(IE)에서는 항상 ‘기본값’을 넣어주세요. IE 사용자를 비롯한 모든 사용자에게 깔끔한 프롬프트를 보여주려면 아래와 같이 두 번째 매개변수를 항상 전달해 줄 것을 권장합니다.
let test = prompt("Test", ''); // <-- IE 사용자를 위한 매개변수 처리
1.3 confirm
result = confirm(question);
confirm 함수는 매개변수로 받은 question(질문)과 확인 및 취소 버튼이 있는 모달 창을 보여줍니다. 사용자가 확인버튼를 누르면 true, 그 외의 경우는 false를 반환합니다.
let isBoss = confirm("당신이 주인인가요?");
alert( isBoss ); // 확인 버튼을 눌렀다면 true가 출력됩니다.
1.4 요약
브라우저는 사용자와 상호작용할 수 있는 세 가지 기능을 제공해줍니다.
- alert 얼럿 창은 메시지를 보여주는 용도로 사용됩니다.
- prompt 프롬프트 대화상자는 사용자에게 텍스트를 입력하라는 메시지를 띄워줌과 동시에, 입력 필드를 함께 제공합니다. 확인을 누르면 prompt 함수는 사용자가 입력한 문자열을 반환하고, 취소 또는 Esc를 누르면 null을 반환합니다.
- confirm 컨펌 대화상자는 메시지를 띄워줍니다. 사용자가 확인 또는 취소 버튼을 누를 때까지 창은 그대로 떠 있습니다. confirm 함수는 사용자가 확인 버튼을 누르면 true를, 취소 버튼이나 Esc를 누르면 false를 반환합니다. 위 함수들은 모두 모달 창을 띄워주는데, 모달 창이 떠 있는 동안은 스크립트의 실행이 일시 중단됩니다. 사용자가 창을 닫기 전까진 나머지 페이지와 상호 작용이 불가능합니다.
위 메서드엔 두 가지 제약사항이 있습니다.
모달 창의 위치는 브라우저가 결정하는데, 대개 브라우저 중앙에 위치합니다. 모달 창의 모양은 브라우저에 마다 다릅니다. 개발자는 창의 모양을 수정할 수 없습니다. 이런 제약사항은 간결성을 위해 치러야 할 대가입니다. 창을 더 멋지게 꾸미고 복잡한 상호작용을 가능하게 해주는 다른 방법도 있긴 하지만, “멋을 위한 부가 기능”이 필요하지 않다면 지금까지 소개해드린 기본 메서드만으로 충분하다고 생각합니다.
2. 조건부 연산자 if와 ?
조건에 따라 다른 행동을 취해야 할 때가 있습니다. 이럴 땐, if문과 ‘물음표’ 연산자라고도 불리는 조건부 연산자 ?를 사용하면 됩니다.
2.1 if
if(…)문은 괄호 안에 들어가는 조건을 평가하는데, 그 결과가 true이면 코드 블록이 실행됩니다.
let year = prompt('ECMAScript-2015 명세는 몇 년도에 출판되었을까요?', '');
if (year == 2015) alert( '정답입니다!' );
2.2 불린형으로 변환
if (…) 문은 괄호 안의 표현식을 평가하고 그 결과를 불린값으로 변환합니다.
- 숫자 0, 빈 문자열"", null, undefined, NaN은 불린형으로 변환 시 모두 false가 됩니다. 이런 값들은 ‘falsy(거짓 같은)’ 값이라고 부릅니다.
- 이 외의 값은 불린형으로 변환시 true가 되므로 ‘truthy(참 같은)’ 값이라고 부릅니다.
2.3 else, else if절
우리가 생각하는 다른 언어와 같이 동작합니다.
2.4 조건부 연산자 ‘?’
조건에 따라 다른 값을 변수에 할당해줘야 할 때가 있습니다.
let accessAllowed;
let age = prompt('나이를 입력해 주세요.', '');
if (age > 18) {
accessAllowed = true;
} else {
accessAllowed = false;
}
// 위의 if 조건절을 한 줄로 줄일 수 있다.
let accessAllowed = (age > 18) ? true : false;
alert(accessAllowed);
괄호가 있으나 없으나 차이는 없지만, 코드의 가독성 향상을 위해 괄호를 사용할 것을 권유합니다.
2.5 다중 ‘?’
물음표 연산자?를 여러 개 연결하면 복수의 조건을 처리할 수 있습니다.
let age = prompt('나이를 입력해주세요.', 18);
let message = (age < 9) ? '아기야 안녕?' :
(age < 18) ? '안녕!' :
(age < 100) ? '환영합니다!' :
'나이가 아주 많으시거나, 나이가 아닌 값을 입력 하셨군요!';
alert( message );
물음표 연산자를 이런 방식으로 쓰는 걸 처음 본 분이라면 이 코드가 어떻게 동작하는지 파악하기 힘들 수 있습니다. 그러나 주의를 집중하고 보면, 단순히 여러 조건을 나열한 코드임에 불과하다는 것을 알 수 있습니다.
2.6 부적절한 ‘?’
물음표?를 if 대용으로 쓰는 경우가 종종 있습니다.
let company = prompt('자바스크립트는 어떤 회사가 만들었을까요?', '');
(company == 'Netscape') ?
alert('정답입니다!') : alert('오답입니다!');
그런데 이런 식으로 물음표 연산자를 사용하는 것은 좋지 않습니다.
개발자 입장에선 if문을 사용할 때 보다 코드 길이가 짧아진다는 점 때문에 물음표?를 if 대용으로 쓰는 게 매력적일 순 있습니다. 하지만 이렇게 코드를 작성하면 가독성이 떨어집니다.
let company = prompt('자바스크립트의 "공식" 이름은 무엇일까요?', '');
if (company == 'ECMAScript') {
alert('정답입니다!');
} else {
alert('오답입니다!');
}
코드를 읽을 때 우리의 눈은 수직으로 움직입니다. 수평으로 길게 늘어진 코드보단 여러 줄로 나뉘어 작성된 코드 블록이 더 읽기 쉽죠.
물음표 연산자?는 조건에 따라 반환 값을 달리하려는 목적으로 만들어졌습니다. 이런 목적에 부합하는 곳에 물음표를 사용하시길 바랍니다. 여러 분기를 만들어 처리할 때는 if를 사용하세요.
3. 논리 연산자
자바스크립트엔 세 종류의 논리 연산자 ||(OR), &&(AND), !(NOT) 이 있습니다.
연산자에 “논리”라는 수식어가 붙긴 하지만 논리 연산자는 피연산자로 (불린형뿐만 아니라) 모든 유형의 값을 받을 수 있습니다. 연산 결과 역시 모든 유형이 될 수 있습니다.
3.1 || (OR)
전통적인 프로그래밍에서 OR 연산자는 불린값을 조작하는 데 쓰입니다. 인수 중 하나라도 true이면 true를 반환하고, 그렇지 않으면 false를 반환하죠.
alert( true || true ); // true
alert( false || true ); // true
alert( true || false ); // true
alert( false || false ); // false
피연산자가 불린형이 아니면, 평가를 위해 불린형으로 변환됩니다.
예를 들어, 연산 과정에서 숫자 1은 true로, 숫자 0은 false로 바뀌죠.
if (1 || 0) { // if( true || false ) 와 동일하게 동작합니다.
alert( 'truthy!' );
}
3.2 첫 번째 truthy를 찾는 OR 연산자 “||”
위에선 피연산자가 불린값인 경우만을 다뤘습니다. 전통적인 방식이죠. 이제 자바스크립트에서만 제공하는 논리연산자 OR의 “추가”기능에 대해 알아보도록 하겠습니다.
추가 기능은 아래와 같은 알고리즘으로 동작합니다.
OR 연산자와 피연산자가 여러 개인 경우 다음 순서에 따라 연산을 수행합니다.
- 가장 왼쪽 피연산자부터 시작해 오른쪽으로 나아가며 피연산자를 평가합니다.
- 각 피연산자를 불린형으로 변환합니다. 변환 후 그 값이 true이면 연산을 멈추고 해당 피연산자의 (변환 전) 원래 값을 반환합니다.
- 피연산자 모두를 평가한 경우(모든 피연산자가 변환 후 false인 경우)는 마지막 피연산자를 반환합니다.
여기서 핵심은 반환 값이 형 변환을 하지 않은 원래 값이라는 것입니다.
정리해 보자면 이렇습니다. OR 연산자를 여러 개 체이닝(chaining) 하면 첫 번째 truthy를 반환합니다. 피연산자에 truthy가 하나도 없다면 마지막 피연산자를 반환합니다.
alert( 1 || 0 ); // 1 (1은 truthy임)
alert( true || 'no matter what' ); // (true는 truthy임)
alert( null || 1 ); // 1 (1은 truthy임)
alert( null || 0 || 1 ); // 1 (1은 truthy임)
alert( undefined || null || 0 ); // 0 (모두 falsy이므로, 마지막 값을 반환함)
자바스크립트에서만 제공하는 OR 연산자의 추가 기능을 이용하면 다양한 용도로 OR 연산자를 활용할 수 있습니다.
3.2.1 변수 또는 표현식으로 구성된 목록에서 첫 번째 truthy 얻기
let currentUser = null;
let defaultUser = "John";
let name = currentUser || defaultUser || "unnamed";
alert( name ); // 첫 번째 truthy인 "John"이 반환되어 name에 저장되었습니다.
3.2.2 단락 평가 피연산자엔 값뿐만 아니라 임의의 표현식이 올 수도 있습니다. 위에서 설명해 드린 바와 같이 OR||은 왼쪽부터 시작해서 오른쪽으로 평가 및 테스트를 진행하고, truthy를 만나면 평가를 중지하고 그 값을 반환합니다. 왼쪽부터 연산을 시작해 truthy에 도달한 순간 평가를 멈추기 때문에 모든 피연산자를 평가하지 않고 짧게 연산을 끝마칩니다. 이런 과정을 “단락 평가(short circuit evaluation)“라고 부르죠.
두 번째 피연산자가 변수 할당과 같은 부수적인 효과(side effect)를 가지는 표현식 일 때 단락 평가가 어떻게 동작하는지 명확히 볼 수 있습니다.
아래 예시에서 x의 값은 아직 할당되지 않은 상태입니다.
let x;
true || (x = 1);
alert(x); // 표현식 (x = 1)이 평가되지 않았기 때문에 x는 undefined입니다.
위 예시에서 첫 번째 인수가 false라면, ||는 두 번째 인수를 평가하기 때문에 x에 값이 할당됩니다.
let x;
false || (x = 1);
alert(x);
위 두 예시에서 할당은 복잡하지 않고 간단한 부수 효과였습니다. 평가가 진행되지 않으면 그 효과를 알 수 없는 기타 부수 효과가 있을 수도 있죠.
OR을 이런 식으로 활용하면 “if 조건문을 더 짧게” 대체할 수 있습니다. 첫 번째 피연산자를 불린값으로 변환하고, 그 값이 false 라면 두 번째 피연산자를 평가하도록 만들 수 있죠.
코드 이해도 측면에서 “평범한” if문을 사용하는 것이 좋긴 하지만, 가끔은 OR을 사용한 대안이 편리할 수 있습니다.
3.3 && (AND)
전통적인 프로그래밍에서 AND 연산자는 두 피연산자가 모두가 참일 때 true를 반환합니다. 그 외의 경우는 false를 반환하죠.
alert( true && true ); // true
alert( false && true ); // false
alert( true && false ); // false
alert( false && false ); // false
OR 연산자와 마찬가지로 AND 연산자의 피연산자도 타입에 제약이 없습니다.
if (1 && 0) { // 피연산자가 숫자형이지만 논리형으로 바뀌어 true && false가 됨
alert( "if 문 안에 falsy가 들어가 있으므로 alert창은 실행되지 않습니다." );
}
3.4 첫 번째 falsy를 찾는 AND 연산자 “&&”
AND 연산자 &&는 아래와 같은 순서로 동작합니다.
- 가장 왼쪽 피연산자부터 시작해 오른쪽으로 나아가며 피연산자를 평가합니다.
- 각 피연산자를 불린형으로 변환합니다. 변환 후 값이 false이면 평가를 멈추고 해당 피연산자의 (변환 전) 원래 값을 반환합니다.
- 피연산자 모두를 평가한 경우(모든 피연산자가 truthy인 경우)는 마지막 피연산자를 반환합니다.
정리해 보자면 이렇습니다. AND 연산자는 첫 번째 falsy를 반환합니다. 피연산자에 falsy가 없다면 마지막 값을 반환합니다.
위 알고리즘은 OR 연산자의 알고리즘과 유사합니다. 차이점은 AND 연산자가 첫 번째 falsy를 반환하는 반면, OR은 첫 번째 truthy를 반환한다는 것입니다.
// 첫 번째 피연산자가 truthy이면,
// AND는 두 번째 피연산자를 반환합니다.
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5
// 첫 번째 피연산자가 falsy이면,
// AND는 첫 번째 피연산자를 반환하고, 두 번째 피연산자는 무시합니다.
alert( null && 5 ); // null
alert( 0 && "no matter what" ); // 0
// 다음 표현식에선 AND 연산자의 피연산자가 모두 truthy이기 때문에 마지막 피연산자가 반환됩니다.
alert( 1 && 2 && 3 ); // 마지막 값, 3
** AND의 우선순위가 OR보다 높습니다.**
OR 연산자와 마찬가지로 AND 연산자 && 또한 if 문 대용으로 쓸 수 있습니다.
let x = 1;
(x > 0) && alert( '0보다 큽니다!' );
let x = 1;
if (x > 0) {
alert( '0보다 큽니다!' );
}
동일한 동작을 하는 코드지만 &&를 사용한 코드가 더 짧습니다. 그런데 if문을 사용한 예시가 코드에서 무엇을 구현하고자 하는지 더 명백히 드러내고, 가독성도 좋습니다.
3.5 ! (NOT)
논리 연산자 NOT은 느낌표 !를 써서 만들 수 있습니다.
alert( !true ); // false
alert( !0 ); // true
NOT을 두 개 연달아 사용(!!)하면 값을 불린형으로 변환할 수 있습니다.
alert( !!"non-empty string" ); // true
alert( !!null ); // false
이때, 첫 번째 NOT 연산자는 피연산자로 받은 값을 불린형으로 변환한 후 이 값의 역을 반환하고, 두 번째 NOT 연산자는 첫 번째 NOT 연산자가 반환한 값의 역을 반환합니다. 이렇게 NOT을 연달아 사용하면 특정 값을 불린형으로 변환할 수 있습니다.
참고로, 내장 함수 Boolean을 사용하면 !!을 사용한 것과 같은 결과를 도출할 수 있습니다.
alert( Boolean("non-empty string") ); // true
alert( Boolean(null) ); // false
NOT 연산자의 우선순위는 모든 논리 연산자 중에서 가장 높기 때문에 항상 AND나 OR보다 먼저 실행됩니다.
3.6 문제
3.6.1 OR 연산자의 피연산자가 alert 라면?
alert( alert(1) || 2 || alert(3) );
- 정답 : alert 메서드는 값을 반환하지 않습니다. 즉, undefined를 반환하죠.
- 첫 번째 OR는 왼쪽 피연산자인 alert(1)를 평가합니다. 이때 첫 번째 얼럿 창에 1이 출력되죠.
- alert메서드는 undefined를 반환하기 때문에, OR 연산자는 다음 피연산자를 평가하게 됩니다. truthy를 찾기 위해 말이죠.
- 두 번째 피연산자(오른쪽 피연산자)인 2는 truthy이기 때문에 실행이 멈추고 2가 반환됩니다. 반환된 값 2는 제일 바깥 alert의 피연산자가 되어 두 번째 얼럿창에 출력됩니다.
- 평가가 alert(3)까지 진행되지 않기 때문에 3은 출력되지 않습니다.
3.6.2 AND 연산자의 피연산자가 alert 라면?
alert( alert(1) && alert(2) );
얼럿 창엔 1, undefined가 차례대로 출력됩니다.
3.6.3 alert( null || 2 && 3 || 4 );
-> 얼럿 창엔 3이 출력됩니다.