모던 JS 튜토리얼 Part 1. 코어 자바스크립트 문서를 읽고 내용을 정리합니다.
JS는 대부분의 경우 줄 바꿈이 있다면 세미콜론(semicolon)을 생략할 수 있다.
alert('Hello')
alert('World')
하지만, 항상 그런 것은 아니다.
alert(3 +
1
+ 2);
alert("에러가 발생합니다.")
[1, 2].forEach(alert)
결론은, 줄 바꿈으로 문을 나눴더라도 statement 사이엔 세미콜론을 넣는 것이 좋다는 것이다.
- 한 줄 주석 처리 : Ctrl+/
- 여러 줄 주석 처리 : Ctrl+Shift+/
cf) 중첩 주석은 지원하지 않는다. 쓸 경우 에러가 발생한다.
/*
/* 중첩 주석 ?!? */
*/
alert( 'World' );
자바스크립트가 발전함에 따라 새로운 기능이 추가되고 기존 기능 중 일부가 변경되었다. 이로 인한 하위 호환성 문제 때문에, 변경사항 대부분이 기본적으로 활성화되지 않도록 되어있다.
대신 use strict
라는 특별한 지시자를 사용해 엄격 모드(strict mode)를 설정하면, 이 변경사항이 활성화된다.
use strict
는 대부분 스크립트 최상단에 위치시킨다. use strict
위에는 주석만 위치할 수 있고, 그 외의 것들은 엄격모드가 적용되지 않는다.
alert("some code");
// 하단에 위치한 "use strict"는 스크립트 상단에 위치하지 않으므로 무시됩니다.
"use strict";
// 엄격 모드가 활성화되지 않습니다.
모던 자바스크립트에는 '클래스’와 '모듈’이라는 것이 있는데, 이 둘을 사용하면 use strict
가 자동으로 적용된다. 따라서 스크립트에 use strict
를 붙일 필요가 없다.
결론은, 코드를 클래스와 모듈을 사용해 구성한다면
use strict
를 생략해도 된다.
자바스크립트에선 let
키워드를 사용해 변수를 생성한다.
let message;
한 줄에 여러 변수를 선언하는 것도 가능하다.
let user = 'John', age = 25, message = 'Hello';
하지만 가독성을 위해 한 줄에는 하나의 변수를 작성한다.
let user = 'John';
let age = 25;
let message = 'Hello';
cf) var
키워드
만들어진 지 오래된 스크립트에서 let
대신 var
가 작성되어있는 경우가 있다. var
는 let
과 거의 동일하게 동작하지만, var
는 ‘오래된’ 방식이다.
자바스크립트에서는 카멜 표기법(camelCase)을 흔히 사용한다.
ex) myVeryLongName
변화하지 않는 변수를 선언할 때는 const
를 사용한다.
const myBirthday = '18.04.1982';
상수를 사용하는 이유는 변숫값이 절대 변경되지 않을 것이라 확신하면, 값이 변경되는 것을 방지하면서 다른 개발자들에게 이 변수는 상수라는 것을 알리기 위해서이다.
'상수’는 변수의 값이 절대 변하지 않음을 의미한다. 이 상수를 두 종류로 나눌 수 있다.
코드가 실행되기 전에 이미 그 값을 알고 있는 상수. 즉 ‘하드 코딩한’ 값. 실행 전에 이미 값을 알고 있고, 코드에서 직접 그 값을 쓰는 경우
ex) 색상코드 #FFFFFF
런타임 과정에서 계산되지만 최초 할당 이후 값이 변하지 않는 상수
1번의 경우에 대문자 상수를 작성한다.
비교 예제)
const BIRTHDAY = '18.04.1982'; // 1번
const age = someCode(birthday); // 2번
birthday는 이미 알고 있고, 정해져있다. 반면, age는 런타임에 평가된다. 올해의 나이와 내년의 나이는 다르다. 따라서 age는 대문자 상수에 적합하지 않다.
자바스크립트에는 여덟 가지 기본 자료형이 있으나, 변수는 어떤 순간에 문자열일 수 있고 다른 순간엔 숫자가 될 수도 있다.
// 에러 발생하지 않음
let message = "hello";
message = 123456;
이처럼 자료의 타입은 있지만 변수에 저장되는 값의 타입은 언제든지 바꿀 수 있는 언어를 동적 타입(dynamically typed) 언어
라고 부른다.
숫자형엔 일반적인 숫자 외에 Infinity
, -Infinity
, NaN
같은 '특수 숫자 값(special numeric value)이 있다.
alert( 1 / 0 ); // 무한대
alert( Infinity ); // 무한대
alert( "숫자가 아님" / 2 ); // NaN, 문자열을 숫자로 나누면 오류가 발생
alert( "숫자가 아님" / 2 + 5 ); // NaN
자바스크립트에선 (2^53-1)보다 크거나 -(2^53-1) 보다 작은 정수는 '숫자형’을 사용해 나타낼 수 없다.
대신 BigInt
형을 사용한다. 이는 길이에 상관없이 정수를 나타낼 수 있으며, 정수 리터럴 끝에 n을 붙이면 만들 수 있다.
const bigInt = 1234567890123456789012345678901234567890n;
사실 대부분의 상황에서 BigInt
형을 쓸 일은 없지만, 암호 관련 작업같이 아주 큰 숫자가 필요한 상황이거나 아주 높은 정밀도로 작업을 해야 할 때는 필요하다.
let str = "Hello"; //큰따옴표
let str2 = 'Single quotes are ok too'; //작은 따옴표
let phrase = `can embed another ${str}`; //백틱
${…} 안에는 name 같은 변수나 1 + 2 같은 수학 관련 표현식을 넣을 수도 있다.
alert( "the result is ${1 + 2}" );
cf) JS에는 char형이 따로 없다.
어느 자료형에도 속하지 않는 값. null 값은 오로지 null 값만 포함하는 별도의 자료형을 만든다.
let age = null;
자바스크립트의 null은 자바스크립트 이외 언어의 null과 성격이 다르다.
undefined 값도 null 값처럼 자신만의 자료형을 형성한다. undefined는 '값이 할당되지 않은 상태’를 나타낼 때 사용한다.
변수는 선언했지만, 값을 할당하지 않았다면 해당 변수에 undefined가 자동으로 할당된다.
let age;
alert(age); // 'undefined'가 출력됩니다.
null vs. undefined)
다른 자료형은 문자열이든 숫자든 한 가지만 표현할 수 있기 때문에 원시(primitive) 자료형이라고 부르지만, 객체는 데이터 컬렉션이나 복잡한 개체(entity)를 표현할 수 있다.
심볼(symbol)형은 객체의 고유한 식별자(unique identifier)를 만들 때 사용된다.
두 가지 형태의 문법
헷갈리는 예외
typeof null // "object"
typeof alert // "function"
브라우저 환경에서 사용되는 최소한의 사용자 인터페이스 기능인 alert, prompt, confirm에 대해 알아보자.
사용자가 ‘확인(OK)’ 버튼을 누를 때까지 메시지를 보여주는 창이 계속 떠있게 된다.
alert("Hello");
alert은 undefined 값을 반환한다. (아무것도 반환하지 않는다.)
cf) 모달(modal)창
메시지가 있는 작은 창. 사용자는 모달 창이 떠있는 동안 모달 창 바깥에 있는 버튼을 누르는 등 페이지의 나머지 부분과 상호 작용이 불가능하다.
result = prompt(title, [default]);
메세지(title)와 사용자 input field, 확인(OK) 및 취소(Cancel) 버튼이 있는 모달 창이 뜬다. default 값을 넣어주면 기본 input 값이 field에 세팅되어있다.
사용자는 input field에 원하는 값을 입력하고 확인을 누르거나, 취솧 혹은 Esc를 누를 수 있다.
prompt 함수는 사용자가 input field에 기재한 문자열을 반환한다. 사용자가 입력을 취소한 경우는 null이 반환된다.
cf) 인수를 감싸는 대괄호 [...]의 의미
default를 감싸는 대괄호는 이 매개변수가 필수가 아닌 선택값이라는 것을 의미한다.
ex)
let age = prompt('나이를 입력해주세요.', 100);
alert(`당신의 나이는 ${age}살 입니다.`);
result = confirm(question);
매개변수로 받은 question(질문)과 확인 및 취소 버튼이 있는 모달 창을 보여준다.
사용자가 확인 버튼을 누르면 true, 그 외의 경우는 false를 반환한다.
ex)
let isBoss = confirm("당신이 주인인가요?");
alert( isBoss ); // 확인 버튼을 눌렀다면 true가, 취소 버튼을 눌렀다면 false가 나온다.
alert 함수
alert메서드는 매개변수로 문자형을 받지만, 만약 다른 형의 값을 전달받으면 그 값이 문자형으로 자동 변환된다.
String 함수
String(value) 함수는 value를 문자형으로 명시해서 변환해준다.
let value = true;
alert(typeof value); // boolean
value = String(value); // 문자열 "true"로 변환됨
alert(typeof value); // string
false는 문자열 "false"로, null은 문자열 "null"로 변환된다.
alert( "6" / "2" ); // 3, 문자열이 숫자형으로 자동변환된 후 연산이 수행된다
let str = "123";
alert(typeof str); // string
let num = Number(str); // 문자열 "123"이 숫자 123으로 변환됩니다.
alert(typeof num); // number
❗한편, 숫자 이외의 글자가 들어가 있는 문자열을 숫자형으로 변환하려고 하면, 그 결과는 NaN이 된다.
let age = Number("임의의 문자열 123");
alert(age); // NaN
그 외 숫자형으로 변환 시 적용되는 규칙
alert( Number(" 123 ") ); // 123
alert( Number("123z") ); // NaN
alert( Number(true) ); // 1
alert( Number(false) ); // 0
Boolean(value) 함수는 value를 Boolean형으로 바꿔준다.
alert( Boolean(1) ); // true
alert( Boolean(0) ); // false
alert( Boolean("hello") ); // true
alert( Boolean("") ); // false
❗문자열 "0"은 true이다.
alert( Boolean("0") ); // true
alert( Boolean(" ") ); // 공백이 있는 문자열도 비어있지 않은 문자열이기 때문에 true! 숫자형이랑 헷갈리지 말 것
여기서 발표 + 퀴즈내자 !!!!!!!!!!!
alert( 2 ** 2 ); // 4 (2 * 2)
alert( 2 ** 3 ); // 8 (2 * 2 * 2)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)
alert( 4 ** (1/2) ); // 2 (1/2 거듭제곱은 제곱근)
alert( 8 ** (1/3) ); // 2 (1/3 거듭제곱은 세제곱근)
let s = "my" + "string";
alert(s); // mystring
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
+를 제외한 나머지 연산자로 연결되는 피연산자는 숫자로 변환된다.
alert( 6 - '2' ); // 4, '2'를 숫자로 바꾼 후 연산 진행
alert( '6' / '2' ); // 3, 두 피연산자가 숫자로 바뀐 후 연산이 진행
단항연산자가 숫자형이 아닌 다른 자료형 앞에 붙으면, 해당 피연산자는 숫자형으로 변환된다. 즉 Number 함수와 동일한 역할을 하게 된다.
alert( +true ); // 1
alert( +"" ); // 0
let apples = "2";
let oranges = "3";
// 이항 덧셈 연산자가 적용되기 전에, 두 피연산자는 숫자형으로 변화합니다.
alert( +apples + +oranges ); // 5
여기서 알 수 있는 사실 : 단항연산자가 이항연산자보다 우선순위가 높다!
여기도 발표준비~
let a = 1;
let b = 2;
let c = 3 - (a = b + 1);
alert( a ); // 3
alert( c ); // 0
동작 원리 이해용으로 작성된 코드. 직접 코드를 작성할 땐 이런 방식을 사용하지 말 것. 가독성이 떨어진다!
비교 예시)
let counter = 1;
let a = ++counter; // (*)
alert(a); // 2
let counter = 1;
let a = counter++; // (*) ++counter를 counter++로 바꿈
alert(a); // 1
반환 값을 사용하지 않는 경우라면, 전위형과 후위형엔 차이가 없다.
쉼표 연산자(comma operator) ,는 좀처럼 보기 힘들고, 특이한 연산자 중 하나이다. 코드를 짧게 쓰려는 의도로 가끔 사용된다.
쉼표 연산자 ,는 여러 표현식을 코드 한 줄에서 평가할 수 있게 해준다. 이때 표현식 각각이 모두 평가되지만, 마지막 표현식의 평가 결과만 반환되는 점에 유의해야 한다.
let a = (1 + 2, 3 + 4);
alert( a ); // 7 (3 + 4의 결과)
이렇게 마지막 표현식을 제외한 모든 것을 버리는 연산자는 어디서 사용되는 걸까? 여러 동작을 하나의 줄에서 처리하려는 복잡한 구조에서 이를 사용합니다.
// 한 줄에서 세 개의 연산이 수행됨
for (a = 1, b = 3, c = a * b; a < 10; a++) {
...
}
쉼표 연산자를 사용한 트릭은 여러 자바스크립트 프레임워크에서 볼 수 있다. 하지만 쉼표 연산자는 코드 가독성에 도움이 되지 않는다. 따라서 곰곰이 생각해 본 후, 진짜 필요한 경우에만 사용하기를 추천한다.
문자열은 왼쪽부터 사전순으로 문자열을 비교한다.
문자열의 길이가 다를 경우 긴 문자열이 더 크다고 결론낸다.
alert('Z' > 'A'); //true
alert('Glow' > 'Glee'); //true
alert('Bee' > 'Be'); //true
alert('2' > '12'); //true
비교하려는 값의 자료형이 다르면 JS는 이 값들을 숫자형으로 바꾼다.
alert('2' > 1); //true. 2 > 1 → true
alert('01' == 1); //true. 1 == 1 → true
alert(true == 1); //true
alert(false == 0); //true
alert('' == false); //true
비교하려는 값의 자료형이 다르더라도 형 변환 없이 값을 비교한다. 즉 자료형의 동등 여부까지 검사하는 것이다. JS에서는 이것을 대부분 사용한다.
alert(false === 0); //false
피연산자가 null일 때 비교 연산자는 형 변환을 하고, 동등 연산자는 형 변환을 하지 않는다.
alert(null > 0); // false. 0 > 0은 false
alert(null == 0); //false. null이 0으로 바뀌지 않음.
alert(null >= 0); //true. 0 >= 0은 true
피연산자가 undefined일 때, 비교 연산자와 동등 연산자 모두 항상 false를 반환한다.
alert(undefined > 0); // false
alert(undefined < 0); //false
alert(undefined == 0); //false
null과 undefined는 동등 연산자를 취하면 서로 같다. 다른 자료형과는 배타적이다. 둘만 동등하다.
조건부 연산자는 물음표?로 표시한다. 피연산자가 세 개이기 때문에 조건부 연산자를 '삼항(ternary) 연산자’라고 부르는 사람도 있다. JS에서 피연산자를 3개나 받는 연산자는 조건부 연산자가 유일하다.
let result = condition ? value1 : value2;
condition이 truthy라면 value1이, 그렇지 않으면 value 2가 result에 반환된다.
ex)
let accessAllowed = (age > 18) ? true : false;
age > 18 조건을 만족하면 accessAllowed에 true가, 만족하지 않으면 false가 반환된다.
물음표 연산자?를 여러 개 연결하면 복수의 조건을 처리할 수 있다.
let age = prompt('나이를 입력해주세요.', 18);
let message = (age < 3) ? '아기야 안녕?' :
(age < 18) ? '안녕!' :
(age < 100) ? '환영합니다!' :
'나이가 아주 많으시거나, 나이가 아닌 값을 입력 하셨군요!';
alert( message );
물음표 연산자?는 조건에 따라 반환 값을 달리하려는 목적으로 만들어졌다. 이런 목적에 부합하는 곳에 물음표를 사용해야 한다. 여러 분기를 만들어 처리할 때는 if를 사용하는 것이 좋다.
JS에서만 제공하는 논리연산자 OR의 추가 기능에 대해 알아보자.
result = value1 || value2 || value3;
OR 연산자가 여러 개인 경우, OR 연산자 ||는 다음 순서에 따라 연산을 수행한다.
반환 값이 형 변환을 하지 않은 원래 값이라는 것이 중요하다.
alert( 1 || 0 ); // 1 (1은 truthy임)
alert( null || 1 ); // 1 (1은 truthy임)
alert( null || 0 || 1 ); // 1 (1은 truthy임)
alert( undefined || null || 0 ); // 0 (모두 falsy이므로, 마지막 값을 반환함)
cf) 구체적인 활용 방안은 문서 2.11 참고
result = value1 && value2 && value3;
AND 연산자 &&는 아래와 같은 순서로 동작한다.
// 첫 번째 피연산자가 truthy이면,
// AND는 두 번째 피연산자를 반환합니다.
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5
// 첫 번째 피연산자가 falsy이면,
// AND는 첫 번째 피연산자를 반환하고, 두 번째 피연산자는 무시합니다.
alert( null && 5 ); // null
alert( 0 && "아무거나 와도 상관없습니다." ); // 0
alert( 1 && 2 && null && 3 ); // null
alert( 1 && 2 && 3 ); // 마지막 값, 3
NOT을 두 개 연달아 사용(!!)하면 값을 Boolean형으로 변환할 수 있다.
alert(!!"non-empty string"); //true
alert(!!null); //false
a ?? b
아래의 코드와 동일한 기능을 한다.
x = (a !== null && a !== undefined) ? a : b;
nullish 병합 연산자 ??를 사용하면 값이 정해진 변수를 간편하게 찾아낼 수 있다.
let firstName = null;
let lastName = null;
let nickName = "바이올렛";
// null이나 undefined가 아닌 첫 번째 피연산자
alert(firstName ?? lastName ?? nickName ?? "익명의 사용자"); // 바이올렛
둘은 매우 비슷해보이지만 중요한 차이점이 있다.
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
'?' 오른쪽엔
break
나continue
가 올 수 없다.
if (i > 5) {
alert(i);
} else {
continue;
}
이 코드를 삼항 연산자로 나타낸다고 해보자.
(i > 5) ? alert(i) : continue; // 여기에 continue를 사용하면 안 됩니다.
이 코드는 에러를 발생시킨다.
평범한 break 지시자를 사용하면 안쪽에 있는 반복문만 빠져나올 수 있다. 그러나 중첩 반복문을 포함한 반복문 두 개 모두를 빠져나와야 한다면, 이럴 때 레이블을 사용할 수 있다.
레이블(label) 은 반복문 앞에 콜론과 함께 쓰이는 식별자이다.
labelName: for (...) {
...
}
반복문 안에서 break <labelName>문을 사용하면 레이블에 해당하는 반복문을 빠져나올 수 있다.
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`(${i},${j})의 값`, '');
// 사용자가 아무것도 입력하지 않거나 Cancel 버튼을 누르면 두 반복문 모두를 빠져나옵니다.
if (!input) break outer; // (*)
// 입력받은 값을 가지고 무언가를 함
}
}
alert('완료!');
위 예시에서 break outer는 outer라는 레이블이 붙은 반복문을 찾고, 해당 반복문을 빠져나오게 해준다. 따라서 제어 흐름이 (*)에서 alert('완료!')로 바로 바뀐다.
continue 지시자를 레이블과 함께 사용하는 것도 가능하다. 레이블이 붙은 반복문의 다음 이터레이션이 실행된다.
function showMessage() {
alert( '안녕하세요!' );
}
showMessage();
showMessage();
function showMessage(from, text) { // from, text : 매개변수
alert(from + ': ' + text);
}
showMessage('Ann', 'Hello!'); // Ann, Hello : 인수
함수 호출 시 매개변수에 인수를 전달하지 않으면 그 값은 undefined
가 된다.
function showMessage(from, text) {
alert(from + ': ' + text);
}
showMessage("Ann");
이렇게 코드를 작성해도 에러가 발생하지 않고, 매개변수 text에 undefined가 할당될 뿐이다. 따라서 에러없이 "Ann: undefined"가 출력된다.
매개변수에 값을 전달하지 않아도 그 값이 undefined가 되지 않게 하려면 함수를 선언할 때 =를 사용해 '기본값(default value)'을 설정해주면 된다.
function showMessage(from, text = "no text given") {
alert( from + ": " + text );
}
showMessage("Ann"); // Ann: no text given
기본값에 함수 표현식도 넣어줄 수 있다.
function showMessage(from, text = anotherFunction()) {
// anotherFunction()은 text값이 없을 때만 호출됨
// anotherFunction()의 반환 값이 text의 값이 됨
}
cf) 매개변수에 기본값을 설정하는 다양한 방법은 2.15 문서 참고
return문이 없거나, return 지시자만 있는 함수는 undefined
를 반환한다.
함수는 어떤 동작을 수행하기 위한 코드를 모아놓은 것이므로, 함수 이름은 대개 동사이다.
그리고 함수는 동작 하나만 담당해야 한다. 함수는 간결하고 한 가지 기능만 수행할 수 있게 만들어야 한다.
함수 선언 방식 외에 함수 표현식(Function Expression) 을 사용해서 함수를 만들 수 있다.
let sayHi = function() {
alert( "Hello" );
};
함수를 생성하고 변수에 값을 할당하는 것처럼 함수가 변수에 할당되었다. 즉 함수를 만들고 그 함수를 변수 sayHi
에 할당한 것이다.
함수는 값이기 때문에 alert를 이용하여 함수 코드를 출력할 수도 있다.
function sayHi() {
alert( "Hello" );
}
alert( sayHi ); // 함수 코드 전체가 보임!
변수를 복사해 다른 변수에 할당하는 것처럼 함수를 복사해 다른 변수에 할당할 수도 있다.
function sayHi() { // (1) 함수 생성
alert( "Hello" );
}
let func = sayHi; // (2) 함수 복사
func(); // Hello // (3) 복사한 함수를 실행(정상적으로 실행됩니다)!
sayHi(); // Hello // 본래 함수도 정상적으로 실행됩니다.
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
function showOk() {
alert( "동의하셨습니다." );
}
function showCancel() {
alert( "취소 버튼을 누르셨습니다." );
}
// 사용법: 함수 showOk와 showCancel가 ask 함수의 인수로 전달됨
ask("동의하십니까?", showOk, showCancel);
함수 ask의 인수, showOk와 showCancel은 콜백 함수 또는 콜백이라고 불린다.
함수를 함수의 인수로 전달하고, 필요하다면 인수로 전달한 그 함수를 나중에 호출(called back)하는 것이 콜백 함수의 개념이다. 위 예시에선 사용자가 "yes"라고 대답한 경우 showOk가 콜백이 되고, "no"라고 대답한 경우 showCancel가 콜백이 된다.
아래와 같이 함수 표현식을 사용하면 코드 길이가 짧아진다.
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
ask(
"동의하십니까?",
function() { alert("동의하셨습니다."); },
function() { alert("취소 버튼을 누르셨습니다."); }
);
1. 문법에서 차이가 있다
// 함수 선언문
function sum(a, b) {
return a + b;
}
// 함수 표현식
let sum = function(a, b) {
return a + b;
};
2. JS 엔진이 함수를 언제 생성하는지가 다르다
함수 표현식은 실제 실행 흐름이 해당 함수에 도달했을 때 함수를 생성한다. 따라서 실행 흐름이 함수에 도달했을 때부터 해당 함수를 사용할 수 있다.
위 예시에서, 스크립트가 실행되고 실행 흐름이 let sum = function…의 우측(함수 표현식)에 도달 했을때 함수가 생성된다. 이때 이후부터 해당 함수를 사용(할당, 호출 등)할 수 있다.
하지만 함수 선언문은 함수 선언문이 정의되기 전에도 호출할 수 있다.
따라서 전역 함수 선언문은 스크립트 어디에 있느냐에 상관없이 어디에서든 사용할 수 있다.
예시를 살펴보자.
//함수 선언문
sayHi("John"); // Hello, John
function sayHi(name) {
alert( `Hello, ${name}` );
}
//함수 표현식
sayHi("John"); // error!
let sayHi = function(name) { // (*) 마술은 일어나지 않습니다.
alert( `Hello, ${name}` );
};
3. scope가 다르다
// 함수 선언문
let age = prompt("나이를 알려주세요.", 18);
// 조건에 따라 함수를 선언함
if (age < 18) {
function welcome() {
alert("안녕!");
}
} else {
function welcome() {
alert("안녕하세요!");
}
}
// 함수를 나중에 호출합니다.
welcome(); // Error: welcome is not defined
함수 선언문은 함수가 선언된 코드 블록 안에서만 유효하기 때문에 이런 에러가 발생한다.
let age = prompt("나이를 알려주세요.", 18);
let welcome;
if (age < 18) {
welcome = function() {
alert("안녕!");
};
} else {
welcome = function() {
alert("안녕하세요!");
};
}
welcome(); // 제대로 동작합니다.
함수 표현식을 사용하면 에러가 발생하지 않는다. if문 밖에 선언한 변수 welcome에 함수 표현식으로 만든 함수를 할당하면 되기 때문이다.
그럼 어떤 것을 사용하는게 좋을까?
함수 선언문을 이용해 함수를 선언하는 걸 먼저 고려하는 게 좋다. 함수 선언문으로 함수를 정의하면, 함수가 선언되기 전에 호출할 수 있어서 코드 구성을 좀 더 자유롭게 할 수 있고, 가독성도 좋아지기 때문이다. 그러나 어떤 이유로 함수 선언 방식이 적합하지 않거나, (위 예제와 같이) 조건에 따라 함수를 선언해야 한다면 함수 표현식을 사용해야 한다.
함수 표현식보다 단순하고 간결한 문법으로 함수를 만들 수 있는 방법이 있다. 바로 화살표 함수(arrow function)를 사용하는 것이다.
let func = (arg1, arg2, ...argN) => expression
이 함수는 아래 함수와 동일하다.
let func = function(arg1, arg2, ...argN) {
return expression;
};
좀 더 구체적인 예시를 보자.
let sum = (a, b) => a + b;
/* 위 화살표 함수는 아래 함수의 축약 버전입니다.
let sum = function(a, b) {
return a + b;
};
*/
alert( sum(1, 2) ); // 3
let double = n => n * 2;
// let double = function(n) { return n * 2 }과 거의 동일합니다.
alert( double(3) ); // 6
let sayHi = () => alert("안녕하세요!");
sayHi();
화살표 함수는 함수 표현식과 같은 방법으로 사용할 수 있다. 아래 예시와 같이 함수를 동적으로 만들 수 있다.
let age = prompt("나이를 알려주세요.", 18);
let welcome = (age < 18) ?
() => alert('안녕') :
() => alert("안녕하세요!");
welcome();
let sum = (a, b) => { // 중괄호는 본문 여러 줄로 구성되어 있음을 알려줍니다.
let result = a + b;
return result; // 중괄호를 사용했다면, return 지시자로 결괏값을 반환해주어야 합니다.
};
alert( sum(1, 2) ); // 3