인터넷에서 우리가 만나는 모든 웹 페이지가 단순히 글과 이미지로만 구성된 것은 아닌데요. 버튼을 클릭하거나 스크롤을 내리고, 동영상을 재생하는 등의 작업들이 함께 하기 때문이죠. 그곳에는 자바스크립트가 있습니다. 만일 프로그래밍을 처음 접한 분이라면 자바스크립트는 동적인 웹 페이지를 만드는데 즉시 활용할 수 있는 도구로서 즐거움과 재미를 더해줄 것이라고 생각합니다. 이 글에서는 코드 한 줄도 알지 못하는 초보자라도 가능한 알기 쉽게 자바스크립트의 기본 문법을 정리해보았습니다. 그럼 자바스크립트의 문법을 하나씩 익혀볼까요?
1.자바스크립트란 무엇일까?
1)자바스크립트의 정의
자바스크립트는 웹 페이지를 동적으로 만들어주는 프로그래밍 언어인데요. HTML과 CSS와 함께 웹 개발의 기본 요소 중의 하나입니다. 주로 사용자가 바라보는 화면을 구성합니다. 다시 말해, 클라이언트 측에서 주로 실행됩니다. 자바스크립트는 1995년에 넷스케이프 브렌던 아이크에 의해 개발되었고요. 현재 자바스크립트의 표준화된 버전은 ES6+입니다.
2)자바스크립트의 주요 특징
- 인터프리터 언어 : 작성된 코드를 한 줄씩 바로 읽어서 실행합니다. 별도로 프로그램을 컴파일(미리 번역)하지 않아도 웹 브라우저에서 곧바로 동작합니다.
- 동적 타이핑 : 변수를 선언할 때 자료형(숫자나 문자)을 미리 정하지 않아도 됩니다. 자바스크립트가 알아서 변수에 담긴 값을 보고 판단하죠.
- 이벤트 기반 및 비동기 처리 : 동시에 여러 작업을 처리할 수 있습니다. 버튼을 클릭하면 팝업이 뜨거나, 웹 페이지에서 데이터를 받아올 때 기다리고만 있는 것이아니라 다른 작업도 가능하게 만들어줍니다.
- 크로스 플랫폼 지원 : 자바스크립트는 웹 브라우저 외에도 서버, 앱에서도 사용할 수 있습니다. 내가 만든 자바스크립트 코드가 PC, 스마트폰 어떤 기기든 돌아간다는 말입니다.
2.기본 문법 이해하기
1)변수와 상수
변수와 상수가 필요한 이유는 데이터를 저장하기 위해서입니다. 변수는 변하는 값을 저장하고 상수는 변하지 않는 값을 저장합니다. 선언 방식은 아래와 같습니다.
var a = 10; // 옛날 방식
let b = 20; // ES6부터 등장
const c = 30; // 상수 선언
■var, let, const의 차이점
- var : 함수 스코프로 중복 선언이 가능합니다. 하지만 var이 가지고 있는 몇 가지 단점 때문에 현재는 사용하지 않습니다.
- let : 블록 스코프로 중복 선언이 불가능합니다. 중복 선언이 불가능하다는 것은 이미 만들어진 변수 즉 저장 공간 안에 값은 변경이 가능하지만 동일 저장 공간은 만들 수 없다는 뜻입니다.
- const : 블록 스코프로 값 변경이 불가능한데요. 상수이기 때문에 값 변경은 불가능합니다.
■스코프와 호이스팅
1)스코프
스코프는 변수나 함수가 유효한 범위를 의미하는데요. 전역 스코프, 함수 스코프, 블록 스코프 세 가지가 있습니다. 그 중에서 함수 스코프와 블록 스코프란 다음과 같습니다.
◆함수 스코프
변수가 함수 내부에서만 유효하고, 함수 외부에서는 접근할 수 없다는 규칙을 말합니다. 예를 들면 다음과 같습니다.
function myFunction() {
var x = 10; // x는 myFunction 함수 내부에서만 유효
console.log(x); // 10
}
console.log(x); // 오류: x는 함수 밖에서 접근할 수 없음
◆블록 스코프
변수가 블록 내부에서만 유효한 규칙을 말합니다. 블록은 {}로 묶인 코드 덩어리를 말하는데요. 예를 들어, 조건문 if나 반복문 for 또는 함수 내부에서도 블록 스코프가 적용됩니다.
if (true) {
let y = 20; // y는 if 블록 안에서만 유효
console.log(y); // 20
}
console.log(y); // 오류: y는 if 블록 밖에서 접근할 수 없음
2)호이스팅
호이스팅은 자바스크립트가 코드를 효율적으로 처리하고 예상치 못한 오류를 방지하기 위해 변수와 함수 선언을 미리 처리하는 메커니즘인데요. 이러한 이유 때문에 변수 선언과 함수 선언이 코드 실행 전에 자동으로 최상단으로 끌어올려지게 됩니다.
◆변수 호이스팅
변수를 선언할 때, let과 const를 사용하는데 어떻게 호이스팅이 동작하는지 예시를 보면 다음과 같습니다.
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 10;
위의 코드에서 코드 에러가 발생한 것을 볼 수 있죠? 실제로 동작하는 방식은 다음과 같습니다.
let x; // 변수 선언이 끌어올려짐
console.log(x); // ReferenceError: Cannot access 'x' before initialization
x = 10; // 값 할당
변수 선언이 끌어올려져 호이스팅되지만, 할당된 값은 끌어올려지지 않기 때문에 출력되는 위치에서 오류가 난 것을 알 수 있습니다.
◆함수 호이스팅
함수 역시 호이스팅 됩니다. 다만, 함수 표현식과 선언식에서 차이가 나타나는데요. 예시를 보면 다음과 같습니다.
[함수 선언식]
hello(); // "Hello, world!"
function hello() {
console.log("Hello, world!");
}
호이스팅에 의해 함수 전체가 끌어올려지게 되는데요. 실제로 위의 코드는 다음과 같이 동작한다고 볼 수 있습니다.
function hello() { // 함수 선언이 끌어올려짐
console.log("Hello, world!");
}
hello(); // "Hello, world!"
함수 선언식은 함수 자체가 끌어올려지기 때문에 코드의 위쪽에서 호출해도 오류 없이 실행되게 됩니다. 그럼 함수 표현식은 어떨까요?
[함수 표현식]
hello(); // TypeError: hello is not a function
var hello = function() {
console.log("Hello, world!");
};
위의 코드는 에러가 발생했죠. 함수 표현식으로 정의된 함수는 함수 선언이 아닌 변수에 함수가 할당되는 형태이기 때문에 함수 자체는 호이스팅이 되지 않기 때문입니다. 실제로는 아래와 같이 동작합니다.
var hello; // 변수 선언이 끌어올려짐
hello = function() { // 함수는 할당된 후에만 사용 가능
console.log("Hello, world!");
};
hello(); // TypeError: hello is not a function
var hello는 끌어올려지지만, 함수 할당은 끌어올려지지 않기 때문에 호출 시점에 hello가 정의되지 않았다며 오류를 발생시킵니다.
정리하자면,
- let과 const로 선언된 변수는 호이스팅되지만 초기화는 원래 위치에서 이루어집니다.
- 함수 선언식은 전체가 호이스팅되기 때문에 코드 어디에 작성하든 호출이 가능합니다.
- 함수 표현식은 변수 선언만 호이스팅되기 때문에 실제 함수는 할당된 후에만 호출이 가능합니다.
스코프와 호이스팅을 잘 이해하면, 자바스크립트에서 변수와 함수가 어떻게 동작하는지 알 수 있기 때문에 이해하고 있어야 합니다.
2)데이터 타입
■기본 데이터 타입
1.숫자(Number)
숫자형으로 정수와 부동소수점(실수)을 모두 나타낼 수 있습니다. Infinity나 Nan역시 숫자에 포함됩니다.
let num1 = 10; // 정수
let num2 = 3.14; // 실수
2.문자열(String)
텍스트 데이터를 다루는 데이터 타입입니다. 작은따옴표, 큰따옴표 또는 백틱을 사용해 문자열을 표현합니다.
let str1 = "Hello, world!";
let str2 = 'JavaScript';
let str3 = `My age is ${30}`; // 템플릿 리터럴
3.논리형(Boolean)
true나 false 두 가지의 값만 가질 수 있는 데이터 타입입니다.
let isActive = true;
let isFinished = false;
4.정의되지 않은 값(undefined)
변수는 선언되었으나 값이 할당되지 않은 경우 자동으로 부여되는 데이터 타입입니다. 함수가 값을 반환하지 않을 때에도 undefined를 반환합니다.
let x;
console.log(x); // 출력: undefined
function test() {}
console.log(test()); // 출력: undefined
5.빈 값(null)
의도적으로 값이 없다는 것을 나타내는 데이터 타입입니다. 값이 없다는 것을 명시적으로 표현할 때 사용합니다.
let person = null;
console.log(person); // 출력: null
6.심볼(Symbol)
고유한 식별자를 생성하는 데이터 타입입니다. 주로 객체의 속성 이름으로 사용되는데요. Symbol()함수로 생성할 수 있지만 동일한 Symbol은 같을 수 없습니다.
let sym1 = Symbol('description');
let sym2 = Symbol('description');
console.log(sym1 === sym2); // 출력: false
7.아주 큰 정수(BigInt)
아주 큰 정수를 표현할 수 있는 데이터 타입입니다. Number 타입의 숫자 범위를 벗어나는 큰 숫자를 다룰 때 사용합니다. 숫자 뒤에는 n을 붙여서 작성해야 합니다.
let bigNumber = 123456789012345678901234567890n;
console.log(bigNumber); // 출력: 123456789012345678901234567890n
■참조 데이터 타입
참조 데이터 타입은 객체를 포함한 데이터 타입을 말합니다. 값이 아닌 주소를 저장한다는 특징을가지고 있는데요. 다시 말해, 참조를 통해 데이터를 다룹니다. 실제 데이터를 복사하는 것이 아닌 해당 데이터가 저장된 메모리 주소를 참조한다는 것입니다. 참조 데이터 타입에는 객체, 배열, 함수가 있습니다.
1.객체(Object)
객체는 키(key)와 값(value)으로 이루어져있습니다. 다음과 같이 사용하는데요.
let person = {
name: "John",
age: 30,
isActive: true
};
console.log(person.name); // 출력: John
console.log(person.age); // 출력: 30
객체는 키와 값을 묶어서 사용할 수 있습니다. 위의 코드를 보면 person이라는 변수명 안에 이름과 나이를 부여해주었는데요. person이라는 객체의 속성들을 묶어서 관리하는 특징을 볼 수 있습니다.
2.배열(Array)
배열은 여러 값을 순서대로 저장할 때 사용합니다. 인덱스를 사용해 각 요소에 접근할 수 있습니다.
let fruits = ["apple", "banana", "cherry"];
console.log(fruits[0]); // 출력: apple
console.log(fruits[1]); // 출력: banana
인덱스는 0부터 시작하며 각 요소에 접근할 수 있습니다.
3.함수(Function)
자바스크립트에서 함수는 객체로서 취급되는데요. 함수 역시 하나의 데이터 타입으로 변수에 저장하거나 다른 함수의 인자로 넘기거나 반환값으로 사용이 가능합니다.
function greet(name) {
return "Hello, " + name;
}
let greetPerson = greet;
console.log(greetPerson("John")); // 출력: Hello, John
위의 예시에서 볼 수 있는 것처럼 함수는 참조형 데이터 타입이기 때문에 함수 자체를 다른 변수에 할당하거나 인자로 넘길 수 있다는 특징을 가지고 있습니다. 위의 greetPerson이라는 변수를 선언한 뒤에 greet함수를 해당 변수에 할당한 것처럼 말이죠. 이 때, greet은 함수이기 때문에, 함수를 변수에 할당하는 것은 함수의 참조(reference)를 전달한다고 할 수 있습니다. 데이터를 복사하는 것이 아니라요. 따라서 greetPerson 변수는 greet함수와 동일한 기능을 수행하게 됩니다.
3)연산자
■주요 연산자
1.산술 연산자
◆덧셈(+)
두 값을 더합니다. 숫자끼리는 산술 연산을 하지만 뭇자열과 숫자를 더하면 문자열로 변환하여 두 값을 이어 붙이게 됩니다.
console.log(5 + 3); // 출력: 8
console.log("Hello" + " World"); // 출력: Hello World
console.log("Number: " + 7); // 출력: Number: 7
◆뺄셈(-)
두 값을 뺍니다. 문자열에 숫자를 빼면 숫자로 변환을 시도하게 됩니다.
console.log(10 - 3); // 출력: 7
console.log("10" - 3); // 출력: 7 (문자열 "10"이 숫자로 변환됨)
◆곱셈(*)
두 값을 곱합니다.
console.log(4 * 3); // 출력: 12
console.log("4" * 3); // 출력: 12 (문자열 "4"가 숫자로 변환됨)
◆나눗셈(/)
첫 번째 값을 두 번째 값으로 나눕니다.
console.log(12 / 4); // 출력: 3
console.log(10 / 3); // 출력: 3.3333333333333335
◆나머지(%)
나눗셈의 나머지를 반환합니다.
console.log(10 % 3); // 출력: 1
console.log(15 % 4); // 출력: 3
◆거듭제곱(**)
첫 번째 값을 두 번째 값만큼 거듭제곱합니다.
console.log(2 ** 3); // 출력: 8 (2의 3제곱)
console.log(5 ** 2); // 출력: 25
◆증가 연산자(++)
변수 값을 1 증가시킵니다. 전위 증가의 경우 증가 후 값을 반환하며, 후위 증가의 경우 현재 값을 반환한 후 증가합니다.
let x = 5;
console.log(++x); // 출력: 6 (증가 후 반환)
console.log(x++); // 출력: 6 (현재 값 반환 후 증가)
console.log(x); // 출력: 7
◆감소 연산자 (–)
변수 값을 1 감소시킵니다. 전위 감소의 경우 감소 후 값을 반환하며, 후위 감소는 현재 값을 반환한 후 감소합니다.
let y = 5;
console.log(--y); // 출력: 4 (감소 후 반환)
console.log(y--); // 출력: 4 (현재 값 반환 후 감소)
console.log(y); // 출력: 3
◆산술 연산의 특징
- 타입 변환을 시도한다.
- 0으로 나누기를 하면 Infinity 또는 -Infinity를 반환한다.
- 0에 0을 나누면 NaN을 반환한다. NaN은 Not a Number의 줄임말이다.
2.비교 연산자
비교 연산자는 두 값이나 표현식을 비교하여 참이나 거짓이냐를 구분하는 불리언 값을 반환합니다. 비교 연산자의 종류는 다음과 같습니다.
비교 연산자 | 설명 | 예시 | 결과 |
== (동등 비교) | 두 값이 동일한지 비교하며, 비교 전에 필요하면 타입 변환을 한다. | 5 == “5” | true |
=== (일치 비교) | 두 값이 동일하고, 타입도 동일한지 비교한다. 타입 변환은 불가능하다. | 5 === “5” | false |
!= (부등 비교) | 두 값이 동일하지 않은지 비교한다. 비교 전에 필요하면 타입 변환이 가능하다. | 5 != “5” | false |
!== (불일치 비교) | 두 값이 동일하지 않거나, 타입이 다르면 true를 반환한다. 타입 변환은 불가능하다. | 5 !==”5″ | true |
< (크기 비교) | 왼쪽 값이 오른쪽 값보다 작은지 확인한다 | 3 < 5 | true |
<== (크기 비교) | 왼쪽 값이 오른쪽 값보다 작거나 같은지 확인한다 | 5 <= 5 | true |
> (크기 비교) | 왼쪽 값이 오른쪽 값보다 큰지 확인한다 | 10 > 7 | true |
>= (크기 비교) | 왼쪽 값이 오른쪽 값보다 크거나 같은지 확인한다 | 8 >= 10 | false |
3.논리 연산자
논리 연산자는 조건문의 흐름을 제어합니다.
◆논리 AND 연산자 (&&)
두 조건이 모두 참일 때 true를 반환합니다. 하나라도 거짓이라면 false를 반환합니다.
console.log(true && true); // 출력: true
console.log(true && false); // 출력: false
console.log(false && true); // 출력: false
console.log(5 && "hello"); // 출력: "hello" (왼쪽이 참, 오른쪽 반환)
console.log(0 && "hello"); // 출력: 0 (왼쪽이 거짓)
◆논리 OR (||)
한쪽이라도 참이면 true를 반환합니다. 두 조건이 모두 다 거짓일 때만 false를 반환하게 됩니다.
console.log(true || false); // 출력: true
console.log(false || false); // 출력: false
console.log("hello" || 5); // 출력: "hello" (왼쪽이 참)
console.log(0 || "world"); // 출력: "world" (왼쪽이 거짓)
◆논리 NOT (!)
조건의 반대 값을 반환합니다.
console.log(!true); // 출력: false
console.log(!false); // 출력: true
console.log(!0); // 출력: true (0은 거짓)
console.log(!""); // 출력: true (빈 문자열은 거짓)
console.log(!"hello"); // 출력: false (문자열은 참)
◆논리 연산자의 특징
- 단락을 평가한다. 예를 들어, &&의 왼쪽이 false면 오른쪽을 평가하지 않는다.
- 논리 연산자는 불리언 값 말고, 값 자체를 반환할 수도 있다.
- false, 0, “”(빈 문자열), null, undefined, NaN은 false로 평가되는 Falsy값이다.
4.할당 연산자
할당 연산자는 변수에 값을 저장하거나 수정할 때 사용합니다. 기본 할당 연산자 외에도 다양하게 결합된 할당 연산자가 있는데 종류는 다음과 같습니다.
할당 연산자 | 설명 | 예시 |
= (기본 할당) | 변수에 값을 할당한다. | x = 10 |
+= (더하기 할당) | 변수에 값을 더하고, 그 결과를 다시 변수에 저장한다. | x += 5 |
-= (빼기 할당) | 변수에서 값을 빼고, 그 결과를 다시 변수에 저장한다. | x -= 3 |
*= (곱하기 할당) | 변수에 값을 곱하고, 그 결과를 다시 변수에 저장한다. | x *= 2 |
/= (나누기 할당) | 변수의 값을 나누고, 그 결과를 다시 변수에 저장한다. | x /= 4 |
%= (나머지 할당) | 변수에 나머지를 저장한다. | x %= 3 |
**== (지수 할당) | 변수의 값을 제곱하고, 그 결과를 다시 변수에 저장한다. | x **= 2 |
&= (AND 할당) | 비트 AND 연산 후 결과를 저장한다. | x &= y; |
|= (OR 할당) | 비트 OR 연산 후 결과를 저장한다. | x |= y; |
^= (XOR 할당) | 비트 XOR 연산 후 결과를 변수에 저장한다. | x ^= y; |
<<= (왼쪽 시프트 할당) | 비트를 왼쪽으로 시프트한 결과를 변수에 저장한다. | x <<= 2; |
>>= (오른쪽 시프트 할당) | 비트를 오른쪽으로 시프트한 결과를 변수에 저장한다. | x >>= 2; |
>>>= (부호 없는 오른쪽 시프트 할당) | 부호 없는 오른쪽 시프트 후 결과를 변수에 저장한다. | x >>>= 2; |
&&= (논리 AND 할당) | 왼쪽 값이 true 일 때만 값을 할당한다. (ES2021 이후) | x &&= y |
||= (논리 OR 할당) | 왼쪽 값이 false일 때만 값을 할당한다. (ES2021 이후) | x || = y |
??= (Null 병합 할당) | 왼쪽 값이 null 또는 undefined일 때만 값을 할당한다. (ES2021 이후) | x ??= y |
5.기타 연산자
◆typeof 연산자
변수나 표현식의 데이터 타입을 확인할 때 사용하는 연산자입니다. 주로 변수의 타입을 동적으로 확인할 때 사용되는데, 데이터 타입의 이름을 문자열로 반환합니다. 예를 들면, 다음과 같습니다.
let num = 42;
console.log(typeof num); // 출력: "number"
let str = "hello";
console.log(typeof str); // 출력: "string"
let isActive = true;
console.log(typeof isActive); // 출력: "boolean"
◆delete 연산자
객체의 속성이나 배열의 요소를 삭제할 때 사용하는 연산자입니다. 객체에서 특정 속성을 삭제하거나 배열에서 특정 인덱스를 없앨 때 유용하게 사용됩니다. 예를 들어, 객체에서 속성을 삭제 할 때는 다음과 같이 코드를 사용합니다.
let person = {
name: "Alice",
age: 25,
};
delete person.age; // 'age' 속성 삭제
console.log(person); // 출력: { name: "Alice" }
3.제어문
1)조건문
조건문은 주어진 조건의 참과 거짓 여부에 따라 다른 코드를 실행할 때 사용합니다. 여러 가지 종류가 있는데요.
◆if문
특정 조건이 참일 때만 코드를 실행합니다.
let age = 18;
if (age >= 18) {
console.log("어른입니다.");
}
◆if else문
조건이 참일 때와 거짓일 때 각각 실행될 코드를 정의할 때 사용합니다.
let score = 75;
if (score >= 80) {
console.log("합격입니다.");
} else {
console.log("불합격입니다.");
}
점수가 80점 이상이면 “합격입니다”를 출력하지만 그렇지 않은 경우 “불합격입니다.”를 출력합니다.
◆if else if else문
여러 조건을 검사하면서 조건이 참이 되는 코드를 실행합니다.
let score = 85;
if (score >= 90) {
console.log("A학점");
} else if (score >= 80) {
console.log("B학점");
} else {
console.log("C학점");
}
예제 코드에서는 점수가 85점이기 때문에 해당하는 B학점이 출력됩니다.
◆switch문
하나의 표현식을 여러 값과 비교하여 실행될 코드를 선택합니다.
let day = 3;
switch (day) {
case 1:
console.log("월요일");
break;
case 2:
console.log("화요일");
break;
case 3:
console.log("수요일");
break;
default:
console.log("알 수 없는 요일");
}
변수 day에 3이라는 값이 할당되어 있습니다. switch문은 이 값을 기반으로 해당하는 case를 찾게 되는데요. 이 경우 day가 case 3에 해당하기 때문에 “수요일”을 출력하게 됩니다. 그리고 break가 있기 때문에 switch문을 종료하게 됩니다. 마지막 default는 이미 break로 빠져나간 상태이기 때문에 실행하지 않습니다.
2)반복문
반복문은 주어진 조건이 참인 동안 코드를 반복적으로 실행합니다.
◆for문
지정한 횟수만큼 반복적으로 실행합니다.
for (let i = 0; i < 5; i++) {
console.log(i); // 0, 1, 2, 3, 4 출력
}
- let i =0; 초기값을 말합니다.
- i < 5; 조건입니다.
- i++ 증감식입니다.
◆while문
조건이 참인 동안 코드를 계속해서 반복 실행합니다.
let i = 0;
while (i < 5) {
console.log(i); // 0, 1, 2, 3, 4 출력
i++;
}
◆do while문
코드를 먼저 한 번 실행한 후에 조건이 참이면 반복해서 실행합니다.
let i = 0;
do {
console.log(i); // 0, 1, 2, 3, 4 출력
i++;
} while (i < 5);
◆for in문
객체의 속성을 순회하기 위해 사용합니다. 형식은 다음과 같은데요.
for (변수 in 객체) {
// 객체의 속성을 반복 실행할 코드
}
예시 코드는 다음과 같습니다.
let person = { name: "Alice", age: 25 }; // 객체 정의
for (let key in person) { //객체의 모든 열거 가능한 속성을 반복
console.log(key, person[key]); // 속성 이름(key)과 속성 값(person[key]) 출력
// name Alice
// age 25
}
예시 코드를 분석해보면 다음과 같습니다.
- 객체 person을 정의했습니다. name의 속성 값은 “Alice”, age의 속성 값은 25입니다.
- let key는 객체의 속성을 의미합니다. name과 age가 있었죠.
- console.log(key, person[key])를 출력하라고 합니다.
- key : 현재 반복 중인 속성의 이름을 말합니다.
- person[key] : 속성의 값을 말합니다.
참고로 for in 루프는 객체의 모든 열거 가능한 속성을 한 번씩만 반복합니다. 따라서 반복이 끝나면 루프가 종료되고 추가적으로 다시 속성을 반복하지 않습니다.
◆for of문
배열이나 이터러블 객체의 값을 순회하는 데 사용합니다. 여기서 배열을 순회한다는 말은 배열의 각 요소를 하나씩 가져와 처리한다는 것을 말합니다. 그리고 이터러블 객체를 순회한다는 말은 순회 가능한 객체(배열, 문자열, Set 등)의 각 값을 하나씩 꺼낸다는 의미입니다.
(참고로, 이터러블이란 하나씩 꺼낼 수 있는 무언가를 말합니다. 예를 들어, 배열은 [1,2,3]처럼 값이 여러 개 들어있는데, 이 값들을 하나씩 꺼내는 것을 순회라고 하고, 배열은 이를 할 수 있으니 이터러블입니다.)
for of문의 형식은 다음과 같습니다.
for (변수 of 이터러블) {
// 이터러블의 각 값을 반복 실행할 코드
}
예시 코드를 볼까요?
let numbers = [1, 2, 3];
for (let num of numbers) {
console.log(num); // 1, 2, 3 출력
}
예시 코드를 분석해보면 다음과 같습니다.
- 배열 numbers를 정의했고, 세 개의 숫자 요소(1,2,3)를 가지고 있습니다.
- 그리고 for of문을 해석하면 반복 가능한 객체의 요소(1,2,3)를 하나씩 순회하여 num변수에 할당하라는 말로 해석할 수 있습니다.
◆break와 continue
1.break
break는 반복문이나 switch문을 즉시 종료시킵니다. 반복문 내에서 조건에 따라 더 이상 반복을 실행하지 않고, 반복문을 빠져나오게 해주는 구문입니다.
for (let i = 0; i < 10; i++) {
if (i === 5) {
break; // i가 5일 때 반복문 종료
}
console.log(i); // 0, 1, 2, 3, 4 출력
}
위의 예시의 경우 i가 5일 경우 반복문을 종료하게 됩니다. 조건을 만족했기 때문에 더 이상 이후의 코드가 실행되지 않고 반복문이 종료됩니다.
2.continue
continue는 반복문 내에서 현재 반복을 건너뛰고, 다음 반복을 시작하게 합니다. 다시 말해, continue가 실행되면 반복문 안에서 남은 코드를 실행하지 않고 바로 다음 반복으로 넘어가게 됩니다.
for (let i = 0; i < 10; i++) {
if (i === 5) {
continue; // i가 5일 때는 아래 코드를 건너뛰고, 다음 반복으로 넘어감
}
console.log(i); // 0, 1, 2, 3, 4, 6, 7, 8, 9 출력
}
예시 코드에서도 알 수 있듯이, i가 5라는 조건이 충족된 경우 해당 조건은 건너뛰고 다음 반복으로 넘어가게 됩니다. 출력값 역시 5라는 숫자를 제외한 나머지 값들이 출력된 결과를 볼 수 있습니다.
4.함수
1)함수 선언과 호출
함수를 선언하는 방식은 다음과 같습니다.
function 함수이름(매개변수1, 매개변수2, ...) {
// 함수가 실행될 때 수행할 코드
return 결과값; // (선택 사항)
}
그리고 함수의 선언과 호출을 통한 실제 예시 코드를 적용해보면 다음과 같습니다.
// 함수 선언
function add(a, b) {
return a + b;
}
// 함수 호출
let result = add(5, 7); // 함수 실행 후 반환된 값을 저장
console.log(`결과: ${result}`); // "결과: 12" 출력
먼저, 함수 add를 선언했습니다. 그리고 a와b라는 매개변수를 지정해주었습니다. 반환값은 a와b를 더한 값입니다. result 변수에 add함수의 반환된 값을 저장하라는 호출이 있었죠. 출력 결과 인수 5,7을 더한 값인 12가 출력된 것을 볼 수 있습니다.
용어정리!
- 매개변수 : 함수가 호출될 때 외부로부터 전달받는 입력값을 말합니다.
- 인수 : 함수 호출 시 매개변수에 전달하는 실제 값을 말합니다.
2)화살표 함수
화살표 함수는 ES6에서 도입되기 시작했는데요. 좀 더 간결한 방식으로 함수를 표현하기 위해 설계되었습니다. 기본 문법은 다음과 같습니다.
const 함수이름 = (매개변수1, 매개변수2, ...) => {
함수 본문;
};
- => 기호를 사용해 함수를 정의합니다.
- function 키워드를 사용하지 않습니다.
- 함수의 결과를 반환할 때 return 키워드 없이 간단히 작성할 수 있습니다. 단, 단일 표현식일 때 말이죠.
- 본문이 여러 줄이면 return 키워드를 명시해야 합니다.
3)함수 표현식과 선언식의 차이
함수 선언식과 표현식의 가장 큰 차이는 호이스팅의 여부입니다. 예시 코드를 볼까요?
// 함수 선언식
sayHello(); // 정상적으로 호출 가능
function sayHello() {
console.log("안녕하세요!");
}
// 함수 표현식
// sayHi(); // 오류 발생: Cannot access 'sayHi' before initialization
const sayHi = function () {
console.log("안녕하세요!");
};
sayHi(); // 정상적으로 호출 가능
함수 선언식에서 sayHello()가 함수 정의가 되기도 전인 가장 최상단에 있습니다. 하지만 호출이 가능한데요. 그 이유는 호이스팅이 가능하기 떄문입니다.
반대로, 함수 표현식에서 sayHi()는 오류를 발생시켰습니다. 표현식에서는 호이스팅이 되지 않기 때문입니다. 함수가 정의되기 전에 호출하려고 하면 오류가 발생하죠. 이러한 함수 표현식은 선언된 후에만 호출할 수 있기 때문에 동적 정의나 콜백 함수에 유용하게 사용됩니다.
4)즉시 실행 함수(IIFE)
Immediately Invoked Function Expression의 줄임말로 자바스크립트에서 정의되자마자 바로 실행되는 함수입니다. 주로 코드를 독립적인 범위(스코프) 내에서 실행하기 위해 사용합니다. 즉시 실행 함수는 함수 표현식 형태로 정의하는데, 함수 정의 뒤에 ()를 붙여서 실행합니다. 기본 문법 예시는 다음과 같습니다.
(function () {
// 코드 내용
})();
또는,
(() => {
// 코드 내용
})();
즉시 실행 함수는 몇 가지 특징을 가지고 있는데요.
- 함수가 선언됨과 동시에 실행되기 때문에 따로 호출하지 않아도 된다.
- 함수 내부에 선언된 변수나 함수는 외부에서 접근할 수 없다. 이는, 전역 변수 오염을 방지하게 해준다.
- 익명 함수로 작성할 수 있다.
5.예외 처리와 디버깅
예외 처리와 디버깅은 코드의 안정성을 높이고, 오류를 추적하며, 효울적으로 문제를 해결하도록 도와줍니다.
1)예외처리
여기서 말하는 예외는 코드 실행 중에 발생하는 오류를 말합니다. 예외 처리를 통해서 프로그램 중단을 막고 오류가 발생한 부분을 처리하기 위해 예외 처리를 사용합니다. 예외 처리는 try, catch, finally구문을 사용해 구현할 수 있습니다.
◆try-catch-finally구문
try {
let result = 10 / 0; // 오류가 발생하지 않음
console.log(result);
} catch (error) {
console.log("오류가 발생했습니다: " + error); // 오류 처리
} finally {
console.log("이 코드는 항상 실행됩니다."); // 예외 여부와 상관없이 실행
}
- try : 오류가 발생할 가능성이 있는 코드를 입력합니다.
- catch : 오류가 발생하면 실행합니다. 오류를 잡아 처리할 수 있습니다.
- finally : 오류가 발생하든 그렇지 않든 항상 실행되는 코드로, 리스소 정리에 사용합니다.
이 외에 예외 객체(Error Object), 사용자 정의 오류 던지기(Throw)가 있습니다.
2)디버깅
디버깅은 코드에 숨겨져있는 버그를 찾고, 수정하는 과정을 말합니다. 자바스크립트에서는 다양한 방법으로 디버깅을 할 수 있습니다.
◆console.log() 사용하기
console.log()를 사용해 변수나 함수의 상태를 출력하는 것인데요. 변수의 값이나 함수 실행 결과 등을 추적하므로써 중간 중간 코드 흐름을 확인할 수 있습니다.
let x = 10;
let y = 0;
console.log("x:", x); // x: 10
console.log("y:", y); // y: 0
let result = x / y;
console.log("결과:", result); // NaN (0으로 나누기)
위의 코드는 y가 0이기 때문에 0으로 나눈 출력값 NaN 또는 Infinity를 내놓게 됩니다. 의도치 않은 출력값이기 때문에 문제를 해결할 필요가 있다는 점을 알 수 있습니다.
◆debugger 키워드 사용하기
자바스크립트에는 debugger라는 내장 키워드가 있기 때문에 이를 코드 중간에 넣게되면 브라우저의 디버깅 도구를 실행할 수 있습니다. 코드 실행을 멈추고 현재 상태를 분석하는 것이죠.
function testDebugger() {
let a = 10;
let b = 5;
debugger; // 여기서 코드 실행이 멈추고 디버깅 도구가 활성화됩니다.
let result = a + b;
console.log(result);
}
testDebugger();
이 외에도 브라우저의 개발자 도구인 DevTools를 활용하거나 브라우저 콘솔에서 오류 메시지를 확인하여 문제의 원인을 추적할 수 있습니다.