💡 해당 글은 모던 자바스크립트 튜토리얼을 보고 재정리한 글입니다
var
, let
, const
를 사용해 변수를 선언할 수 있다.
선언된 변수엔 데이터를 저장할 수 있다.
let
– 모던한 변수 선언 키워드var
– 오래된 변수 선언 키워드, 잘 사용하지 않음, ( let
과의 미묘한 차이점 존재, scrope 차이)const
– let
과 비슷하지만, 변수의 값을 변경할 수 없음변수명은 변수가 담고 있는 것이 무엇인지 쉽게 알 수 있도록 지어져야 함
자바스크립트에는 여덟 가지 기본 자료형이 존재
숫자형
: 정수, 부동 소수점 숫자 등의 숫자를 나타낼 때 사용. (정수의 한계 → )bigint
: 길이 제약 없이 정수를 나타낼 수 있음 (끝에 n)string
: 빈 문자열이나 글자들로 이뤄진 문자열을 나타낼 때 사용.boolean
: true
, false
를 나타낼 때 사용.null
: null
값만을 위한 독립 자료형. 알 수 없는 값을 나타냄.undefined
: undefined
값만을 위한 독립 자료형. 할당되지 않은 값을 나타냄.object
: 복잡한 데이터 구조를 표현할 때 사용.symbol
: 객체의 고유 식별자를 만들 때 사용.typeof
연산자는 피연산자의 자료형을 알려줌
typeof x
또는 typeof(x)
형태로 사용.null
의 typeof 연산은 "object"
인데, 이는 언어상 오류임 ! null은 object가 ❌alert
, prompt
, confirm
: 브라우저 환경에서 사용되는 최소한의 사용자 인터페이스 기능
alert
사용자가 “확인(OK)” 버튼을 누를 때까지 계속 떠있는 창을 반환
메세지가 있는 작은 창을 Modal Window 라고 부름
Modal이란 단어에는 페이지의 나머지 부분과 상호 작용이 불가능하다는 의미가 내포되어 있음
▶️ 사용자는 모달 창 바깥에 있는 버튼을 누른다든가 하는 행동을 할 수 없음
alert("Hello");
prompt
브라우저에서 제공하는 prompt
함수는 두 개의 인수를 받음
result = prompt(title, [default]);
함수가 실행되면 텍스트 메시지와 입력 필드(input field), 확인(OK) 및 취소(Cancel) 버튼이 있는 모달 창을 띄워줌
title
: 사용자에게 보여줄 문자열
default
: 입력 필드의 초깃값(선택값)
prompt
함수는 사용자가 입력 필드에 기재한 문자열을 반환!
사용자가 입력을 취소한 경우는 null
이 반환됨.
let age = prompt('나이를 입력해주세요.', 100);
alert(`당신의 나이는 ${age}살 입니다.`); // 당신의 나이는 100살입니다
confirm
result = confirm(question);
confirm
함수는 매개변수로 받은 question(질문)
과 확인 및 취소 버튼이 있는 모달 창을 보여줌
사용자가 확인버튼를 누르면 true
, 그 외의 경우는 false
를 반환
위 함수들은 모두 모달 창을 띄워주는데, 모달 창이 떠 있는 동안은 스크립트의 실행이 일시 중단됨.
사용자가 창을 닫기 전까진 나머지 페이지와 상호 작용이 불가능
위에서 살펴본 세 함수(alert
, prompt
, confirm
)엔 두 가지 제약사항이 존재
숫자형으로 변환
전달받은 값 | 형 변환 후 |
---|---|
undefined | NaN |
null | 0 |
true / false | 1 / 0 |
string | 전달받은 문자열을 “그대로” 읽되, 처음과 끝의 공백을 무시합니다. 문자열이 비어있다면 0이 되고, 오류 발생 시 NaN이 됩니다. |
boolean 형으로 변환
전달받은 값 | 형 변환 후 |
---|---|
0, null, undefined, NaN, "" | false |
그 외의 값 | true |
동등 연산자equality operator (==
는 0
과 false
를 구분하지 못함
""
와 false
도 !위 문제는 동등 연산자가 형이 서로 다른 피연산자를 비교할 때, 피연산자를 숫자로 바꾸기 때문에 발생함
▶️ 형변환 규칙에 따르면, 빈 문자열""
과 false
는 숫자로 바꾸면 0
이 된다.
일치 연산자identity operator (===
) 를 사용하면 형 변환 없이 값을 비교할 수 있음 !
일치 연산자는 엄격한strict 동등 연산자이다.
자료형의 동등 여부까지 검사하기 때문에 피연산자 a
와 b
의 자료형이 다를 경우 a===b
는 false
를 반환함
마찬가지로, 불일치 연산자 !== 는 부등 연산자 !=의 strict version
null
vs undefined
null
이나 undefined
를 다른 값과 비교할 땐 예상치 않은 일들이 발생함
일치 연산자 ===
를 사용하여 null
과 undefined
를 비교
두 값의 자료형이 다르기때문에 거짓 반환
alert( null === undefined ); // false
동등 연산자 ==
를 사용하여 null
과 undefined
를 비교
동등 연산자를 사용해 null
과 undefined
를 비교하면 특별한 규칙이 적용돼 true
가 반환됨
동등 연산자는 null
과 undefined
를 '각별한 커플’처럼 취급
alert( null == undefined ); // true
산술 연산자나 기타 비교 연산자 <
, >
, <=
, >=
를 사용하여 null
과 undefined
를 비교
null
과 undefined
는 숫자형으로 변환.
null
은 0
, undefined
는 NaN
으로 변함
⬇️ 위에서 살펴본 세 가지 규칙들이 만들어낸 흥미로운 에지 케이스(edge case) ⬇️
null vs 0
alert( null > 0 ); // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true
(3)이 true라면, (1)이나 (2) 둘 중 하나는 true이어야하는데, 둘 다 거짓을 반환 중
➡️ 동등 연산자 ==
와 기타 비교 연산자 <
, >
, <=
, >=
의 동작 방식이 다르기 때문
(1)에서 null > 0
이 거짓을, (3)에서 null >= 0
이 참을 반환하는 이유 ?
→ 기타 비교 연산자의 동작 원리에 따라, null
이 숫자형으로 변환돼 0
이 되기 때문
동등 연산자 ==
는 피연산자가 undefined
나 null
일 때 형 변환을 하지 않음
→ undefined
와 null
을 비교하는 경우에만 true
를 반환
→ 그 이외의 경우(null
이나 undefined
를 다른 값과 비교할 때)는 무조건 false
를 반환합
→ (2) 결과에 대한 설명
비교가 불가능한 undefined
alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)
→ (1), (2)에서는 undefined
가 NaN으로 변환됨
→ (3)에서는 undefined
는 null
이나 undefined
만 같게 취급
정리
⚠️ 일치 연산자 ===
를 제외한 비교 연산자의 피연산자에 undefined
나 null
이 오지 않도록 특별히 주의
→ C++ 과 비슷한 문법 !
⚠️ 주 의 사 항 ⚠️
// (1) 안 좋은 예시
let company = prompt('자바스크립트는 어떤 회사가 만들었을까요?', '');
(company == 'Netscape') ?
alert('정답입니다!') : alert('오답입니다!');
// (2) 바른 코드
let company = prompt('자바스크립트는 어떤 회사가 만들었을까요?', '');
if (company == 'Netscape') {
alert('정답입니다!');
} else {
alert('오답입니다!');
}
(1) 코드에서는 평가 결과를 변수에 할당하지 않고, 결과에 따라 실행되는 표현식이 달라지도록 함
➡️코드 길이는 짧아졌으나, 가독성이 떨어진다는 문제점이 존재 !
(2) if를 사용해 변형한 코드
➡️코드를 읽을때, 눈은 수평으로 움직이기 때문에, 여러 줄로 나뉘어 작성된 코드 블록이 더 읽기 쉬움
if ("0") {
alert( 'Hello' );
}
➡️ 비어있는 문자열을 제외한 모든 문자열은 논리 평가시 True를 반환하기때문에 해당 코드는 실행됨 !
첫 번째 truthy를 찾는 OR 연산자 ||
OR 연산자와 피연산자가 여러개인 경우
result = value1 || value || value3;
false
인 경우)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이므로, 마지막 값을 반환함)
OR 연산자의 추가기능을 사용하면 여러 용도를 OR 연산자 활용 가능
변수 또는 표현식으로 구성된 목록에서 첫 번째 truthy 얻기
firstName
, lastName
, nickName
이란 변수가 있는데 이 값들은 모두 옵션 값이라고 가정
→ OR ||
을 사용하면 실제 값이 들어있는 변수를 찾고, 그 값을 보여줄 수 있음
→ 변수 모두에 값이 없는 경우엔 익명
를 보여줌
let firstName = "";
let lastName = "";
let nickName = "바이올렛";
alert( firstName || lastName || nickName || "익명"); // 바이올렛
단락 평가 (short circuit evaluation)
OR||
은 왼쪽부터 시작해서 오른쪽으로 평가를 진행하는데, truthy를 만나면 나머지 값들은 건드리지 않은 채 평가를 멈춤. 이런 프로세스를 '단락 평가’라고 함
단락 평가의 동작 방식은 두 번째 피연산자가 변수 할당과 같은 부수적인 효과를 가지는 표현식일 때 명확히 볼 수 있음
아래 예시를 실행하면 두 번째 메시지만 출력됨
true || alert("not printed");
false || alert("printed");
➡️ 단락 평가는 연산자 왼쪽 조건이 falsy일 때만 명령어를 실행하고자 할 때 자주 쓰입니다.
첫 번째 falsy만 찾는 AND 연산자 ‘&&’
result = value1 && value2 && value3;
false
이면 평가를 멈추고 해당 피연산자의 변환 전 원래 값을 반환true
로 평가되는 경우)OR 연산자와 유사하게 동작
// 첫 번째 피연산자가 truthy이면,
// AND는 두 번째 피연산자를 반환합니다.
alert( 1 && 0 ); // 0
alert( 1 && 5 ); // 5
// 첫 번째 피연산자가 falsy이면,
// AND는 첫 번째 피연산자를 반환하고, 두 번째 피연산자는 무시합니다.
alert( null && 5 ); // null
alert( 0 && "아무거나 와도 상관없습니다." ); // 0
주의사항
⚠️ &&
의 우선순위가 ||
보다 높음
a && b || c && d
는 (a && b) || (c && d)
와 동일하게 동작
⚠️ if
를 ||나 &&로 대체하지 말 것
코드는 항상 구현하고자 하는 것을 명백히 드러내야 함 !
기타
NOT을 두 개 연달아 사용(!!
)하면 값을 불린형으로 변환할 수 있음 (= Boolean()
)
→ NOT 연산자의 우선순위는 모든 논리 연산자 중에서 가장 높음
문제🥸 OR 연산자의 피연산자가 alert라면 ?
alert( alert(1) || 2 || alert(3) );
➡️ 1, 2가 차례대로 출력됨
➡️ alert
메세드는 값을 반환하지 않음 (= undefined
를 반환)
??
(2021.12.21 기준) 추가된지 얼마되지 않은 문법
nullish 병합 연산자 (nullish coalescing operator)
??
를 사용하면 짧은 문법으로 여러 피연산자 중 그 값이 ‘확정되어있는’ 변수를 찾을 수 있음
a ?? b 의 평가 결과는 다음과 같음
a
가 null
도 아니고 undefined
도 아니면 a
b
nullish 병합 연산자 ??
없이 x = a ?? b
와 동일한 코드를 작성하면 아래와 같음
x = (a == undefined || a == null) ? b : a;
x = (a != undefined && a != null) ? a : b;
예시) 세 변수 중 실제 값이 있는 변수의 값을 출력하는데, 세 변수 모두 값이 없다면 '익명의 사용자’가 출력
let firstName = null;
let lastName = null;
let nickName = "바이올렛";
// null이나 undefined가 아닌 첫 번째 피연산자
alert(firstName ?? lastName ?? nickName ?? '익명의 사용자'); // 바이올렛 출력
➡️ 이렇게 ??
를 사용하면 간단하게 값이 정해진 변수를 찾아낼 수 있음
**??
와 ||
의 차이**
두 연산자는 상당히 비슷한 기능을 하는 것 처럼 보이지만 중요한 차이점이 존재함
??
는 첫 번째 defined value 반환||
는 첫 번째 truthy 반환null
과 undefined
, 숫자 0
을 구분 지어 다뤄야 할 때 이 차이점은 매우 중요함
예시 코드
let height = 0;
alert(height || 100); // 100
alert(height ?? 100); // 0
➡️ 0
은 논리 연산에서 false
를 뜻하기 때문에 두 코드의 출력 결과가 다름
➡️ 이 처럼 0이 할당될 수 있는 변수를 사용해 기능을 개발할 때는 ??
가 더 적합 !!
💡 TIP
??
의 연산자 우선순위는 5로 꽤 낮은 편에 속함??
를 사용해 값을 하나 선택할 땐 괄호를 추가하는 게 좋음??
는 &&
나 ||
와 함께 사용하지 못함let x = 1 && 2 ?? 3; // SyntaxError: Unexpected token '??'
해당 이슈를 피하려면 괄호를 사용해야 함 !let x = (1 && 2) ?? 3; // 제대로 동작
alert(x); // 2
다른건 c언어와 비슷함. 레이블만 기억할 것 !!
레이블(label) 은 반복문 앞에 콜론과 함께 쓰이는 식별자
✅ 반복문 안에서 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('완료!');
✅ 레이블을 별도의 줄에 써주는 것도 가능
outer:
for (let i = 0; i < 3; i++) { ... }
⚠️ 레이블은 마음대로 '점프’할 수 있게 해주지 않음 ! ⚠️
레이블을 사용한다고 해서 원하는 곳으로 마음대로 점프할 수 있는 것은 아님
break label; // 아래 for 문으로 점프할 수 없음 !!
label: for (...)
break
와 continue
는 반복문 안에서만 사용할 수 있고, 레이블은 반드시 break
이나 continue
지시자 위에 있어야 함
✅ 함수 요약
함수 선언 방식으로 함수 생성 가능
function 함수이름(복수의, 매개변수는, 콤마로, 구분) {
/* 함수 본문 */
}
undefined
를 반환create…
, show…
, get…
, check…
등의 잘 알려진 접두어를 사용해 이름을 지을 수 있음Javascript는 함수를 “특별한 종류의 값”으로 취급함
다른 언어에서처럼 "특별한 동작을 하는 구조"로 취급되지 않음 !
함수 선언 방식(Function Declaration) 외에 함수 표현식(Function Expression) 을 사용해서 함수를 만들 수 있음
function sayHi() {
alert( "Hello" );
}
위 코드를 함수 표현식으로 함수 생성
✅ 함수를 만들고 그 함수를 변수 sayHi
에 할당하기
let sayHi = function() {
alert( "Hello" );
};
alert(sayHi);
➡️ 함수는 값이기 때문에 alert
를 이용하여 함수 코드를 출력할 수도 있음
➡️ 마지막 줄에서 sayHi
옆에 괄호가 없기 때문에 함수는 실행되지 않음
자바스크립트는 괄호가 있어야만 함수가 호출됨
➡️ 위 코드에선 함수 소스 코드가 문자형으로 바뀌어 출력 !
✅ 변수를 복사해 다른 변수에 할당하는 것처럼, 함수를 복사해 다른 변수에 할당할 수도 있음
function sayHi() { // (1) 함수 생성
alert( "Hello" );
}
let func = sayHi; // (2) 함수 복사
func(); // Hello // (3) 복사한 함수를 실행(정상적으로 실행됩니다)!
sayHi(); // Hello // 본래 함수도 정상적으로 실행됩니다.
✅ 함수 표현식 끝에 세미콜론이 붙는 이유
function sayHi() {
// ...
}
let sayHi = function() {
// ...
};
if { ... }
, for { }
, function f { }
같이 중괄호로 만든 코드 블록 끝엔 ;
이 없어도 됨let sayHi = ...;
과 같은 구문 안에서 값의 역할을 함;
을 붙이는 게 좋음 !!콜백 함수(call back function)
✅ 매개변수가 3개 있는 함수, ask(question, yes, no)
를 작성
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
은 콜백 함수 또는 콜백 이라고 불림showOk
가 콜백이 되고, "no"라고 대답한 경우 showCancel
가 콜백이 됨✅ 함수 표현식을 사용하면 코드 길이가 짧아짐
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
ask(
"동의하십니까?",
function() { alert("동의하셨습니다."); },
function() { alert("취소 버튼을 누르셨습니다."); }
);
ask(...)
안에 “이름 없이” 함수가 선언된 것ask
바깥에선 접근할 수 없음 !함수 표현식 vs 함수 선언문
문법
✔️ 함수 선언문
함수는 주요 코드 흐름 중간에 독자적인 구문 형태로 존재
// 함수 선언문
function sum(a, b) {
return a + b;
}
✔️ 함수 표현식
함수는 표현식이나 구문 구성(syntax construct) 내부에 생성됨
아래 예시에선 함수가 할당 연산자 =
를 이용해 만든 “할당 표현식” 우측에 생성되었음
// 함수 표현식
let sum = function(a, b) {
return a + b;
};
자바스크립트 엔진이 언제 함수를 생성하는지
✔️ 함수 표현식
실제 실행 흐름이 해당 함수에 도달했을 때 함수를 생성
따라서 실행 흐름이 함수에 도달했을 때부터 해당 함수를 사용할 수 있음
✔️ 함수 선언문
함수 선언문이 정의되기 전에도 호출 가능 !
전역 함수 선언문은 스크립트 어디에 있느냐에 상관없이 어디에서든 사용
이게 가능한 이유는 자바스크립트의 내부 알고리즘 때문! 자바스크립트는 스크립트를 실행하기 전, 준비단계에서 전역에 선언된 함수 선언문을 찾고, 해당 함수를 생성함. 스크립트가 진짜 실행되기 전 "초기화 단계"에서 함수 선언 방식으로 정의한 함수가 생성되는 것.
스크립트는 함수 선언문이 모두 처리된 이후에서야 실행됨
따라서 스크립트 어디서든 함수 선언문으로 선언한 함수에 접근할 수 있는 것 !
스코프
“엄격 모드”에서 함수 선언문이 코드 블록 내에 위치하면, 해당 함수는 블록 내 어디서든 접근할 수 있지만, 블록 밖에서는 함수에 접근하지 못함 !
let age = 16; // 16을 저장했다 가정
if (age < 18) {
welcome(); // \ (실행)
// |
function welcome() { // |
alert("안녕!"); // | 함수 선언문은 함수가 선언된 블록 내
} // | 어디에서든 유효합니다
// |
welcome(); // / (실행)
} else {
function welcome() {
alert("안녕하세요!");
}
}
// 여기는 중괄호 밖이기 때문에
// 중괄호 안에서 선언한 함수 선언문은 호출할 수 없음 !!
welcome(); // Error: welcome is not defined
⚠️ 함수 선언문은 함수가 선언된 코드 블록 안에서만 유효하기 때문에 맨 아랫 줄에서 에러 발생
함수 표현식을 사용하면, if
문 밖에서 welcome
함수를 호출할 수 있음 !!
➡️ if
문 밖에 선언한 변수 welcome
에 함수 표현식으로 만든 함수를 할당하면 되죠.
let age = prompt("나이를 알려주세요.", 18);
let welcome;
if (age < 18) {
welcome = function() {
alert("안녕!");
};
} else {
welcome = function() {
alert("안녕하세요!");
};
}
welcome(); // 제대로 동작합니다.
물음표 연산자 ?
를 사용하면 위 코드를 좀 더 단순화할 수 있음
let age = prompt("나이를 알려주세요.", 18);
let welcome = (age < 18) ?
function() { alert("안녕!"); } :
function() { alert("안녕하세요!"); };
welcome();
✅ Summary
let func = (arg1, arg2, ...argN) => expression
arg1..argN
를 받는 함수 func
이 만들어짐func
는 화살표(=>
) 우측의 표현식(expression)
을 평가하고, 평가 결과를 반환let sum = (a, b) => a + b;
/* 위 화살표 함수는 아래 함수의 축약 버전
let sum = function(a, b) {
return a + b;
};
*/
alert( sum(1, 2) ); // 3
(a, b) => a + b
는 인수 a
와 b
를 받는 함수(a, b) => a + b
는 실행되는 순간, 표현식 a + b
를 평가하고 그 결과를 반환✅ 인수가 하나밖에 없다면 인수를 감싸는 괄호를 생략 가능
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
덕분에 좋은 정보 얻어갑니다, 감사합니다.