프론트

[JS] 자바스크립트 기초(2)

hyeppyday 2025. 5. 25. 00:44

1. 호이스팅

저번 글에서 말했던 것처럼 호이스팅에 대해 설명해보도록 하겠다.

호이스팅은 자바스크립트에서 변수와 함수 선언이 해당 범위의 맨 위로 끌어올려지는 듯한 현상으로, 종류로는 변수 호이스팅과 함수 호이스팅이 있다.

 

connectStrings('study', 'hoisting');

function connectStrings(str1, str2) {
	console.log(str1 + str2);
}

 

이렇게 일반적인 방식과는 다르게, 함수가 선언되기 전에 미리 함수를 출력하는 코드를 짜보았다. 하지만 실행해보면 오류가 나지 않고 정상적으로 작동함을 알 수 있다. 이렇게 함수의 선언문을 가장 위쪽으로, 즉 함수가 가지고 있는 스코프의 가장 위쪽으로 끌어올려서 코드를 해석하는 자바스크립트의 작동 방식을 함수 호이스팅이라고 부른다.

 

console.log(num1);
let num1 = 123;

다음과 같이 작성 후 코드를 실행하면, 에러가 발생한다.

 

console.log(num1);
var num2 = 123;

하지만 다음과 같은 코드를 작동시키면 undefined이라는 값이 출력되고 에러는 발생하지 않는다.

 

이 코드가 오류가 뜨는 이유는 단순히 호이스팅이 발생하지 않는 것이 아니라, 다른 이유가 있다. 자바스크립트의 변수 선언 키워드인 let const를 사용해 변수를 선언하고, 변수 선언문의 위쪽에서 let const 키워드로 선언된 변수에 접근하려 한다면 에러가 발생합니다. 이렇게 에러가 발생하는 이유는, var 키워드와는 다르게 let const 키워드로 선언된 변수는, 변수 스코프의 가장 위쪽에서 변수의 초기화가 완료될 때까지 TDZ라는 공간에 있기 때문이다.

 

TDZTemporal Dead Zone의 약자로, 일시적인 사각지대, 다시 말해 변수를 사용하는 것을 허용하지 않는 공간이라고 할 수 있다. 우선, 다음과 같은 코드를, 자바스크립트 엔진이 해석하는 순서로 변경해보겠다.

letconst 키워드는 호이스팅이 발생하지 않는 것이 아니라, var 키워드와는 다르게 변수 스코프의 가장 위쪽에서 변수의 초기화가 완료될 때까지 TDZ라는 공간에 있기 때문에 호이스팅이 발생하지 않는 것처럼 보이는 것이다.

 

자바스크립트 엔진은, 이렇게 var 키워드를 사용해 선언한 변수가 선언문보다 먼저 사용될 경우, 코드를 왼쪽과 같이 해석한다. 변수의 선언문만을, 스코프의 최상단으로 끌어올린 다음, 다음 코드를 실행하고, 그리고 변수에 초기값을 할당한다.

 

2. 함수 표현식과 화살표 함수

자바스크립트에서 함수를 선언하는 방법에는 함수 선언식, 그리고 함수 표현식 이렇게 두 가지 방법이 존재한다.

 

우선 화살표 함수는 기존의 다음과 같은 코드를

function func() {
    console.log('hello javascript');
}

 

const func = () => {
    console.log('hello javascript');
};

이렇게 화살표를 사용해 선언하는 함수이다.

 

함수 표현식은 자바스크립트에서 함수를 선언하는 방법 중 하나로, 이렇게 화살표 함수처럼 변수에 함수를 마치 하나의 값처럼 할당하는 방법이다. 함수를 선언하는 또다른 방식으로는, 위와 같이 function 키워드 옆에 함수의 이름을 작성하고 함수를 선언하는 함수 선언식이 있다.

 

이 둘은 호이스팅의 차이가 있다. 함수 표현식은 변수에 함수를 할당하는 방식이기 때문에, 함수 전체를 호이스팅하는 함수 선언식과는 다르게, 호이스팅이 발생할 경우, 다음과 같이 변수의 호이스팅 방식처럼 변수의 선언 부분과 할당 부분을 나누고, 선언부만 호이스팅한다.

const hoisted;

hoisted(); 

function () {
  console.log("hoisting");
};

변수 호이스팅과 동일하게 letconst로 선언된 함수는 함수가 초기화 되기 전까지 TDZ(Temporal Dead Zone)라는 공간에 머물러 있다. 그렇기 때문에 함수 표현식으로 작성된 함수는 함수 선언식으로 작성된 함수와는 다르게 호이스팅이 발생하지 않는 것 처럼 보인다는 차이점이 있다.

 

이제 본격적으로 화살표 함수에 대해 알아보겠다.

const add = function (a, b) {
    return a + b;
};
console.log(add(10, 20));

다음과 같은 코드를 화살표 함수를 사용하면 함수 표현식을 화살표 모양으로 좀 더 간결하게 사용할 수 있다.

const add = (a, b) => {
    return a + b;
};
console.log(add(10, 20));

const add = (a, b) => a + b;

화살표 함수는 이 코드의 6번째 줄과 마찬가지로 return을 생략해 더욱 더 간단하게 표현할 수 있다.

 

2.1 콜백 함수

콜백 함수란, 다른 함수에 매개 변수로 넘겨준 함수를 의미한다.

const calculate = (a, b, callback) => {
  let result = a + b;
  callback(result);
};

const printResult = (result) => {
  console.log("결과:", result);
};

const doubleResult = (result) => {
  console.log("결과에 2를 곱한 값:", result * 2);
};

calculate(5, 3, printResult);
calculate(5, 3, doubleResult);

이렇게 calculate 함수를 호출할 때, 인수로 특정 함수를 전달하고, calculate 함수에서는 매개변수로 전달받은 함수를 호출하는 코드를 작성하였다. 이때 이렇게 매개변수로 전달 받은 함수를 콜백 함수라고 부르고, 콜백 함수를 사용하면 작성한 코드와 같이 코드의 재사용성을 높이고 함수의 동작을 보다 유연하게 변경할 수 있다.

 

const testFunc = (callback) => {
    callback();
};

testFunc(() => {
    console.log('콜백 함수 테스트');
});

이는 testFunc함수를 선언하고 testFunc 함수 호출하는 코드이다. testFunc를 호출하면서 익명 함수(이름이 없는 함수)를 콜백으로 전달한다. 이 익명 함수는 console.log('콜백 함수 테스트');를 실행하는 함수이다. 결과적으로 callback()이 실행되면서 console.log가 출력된다.

 

3. 객체

객체는 영어로 Object라고 표기하며, 비 원시 타입 자료형으로, 한 번에 여러 개의 데이터 값을 저장할 수 있는 자료형이다. 자바스크립트에서 객체를 생성하는 방법에는 생성자 함수를 사용하는 방법과, 리터럴을 사용하는 방법이 있다.

let obj = new Object();
let obj = {};

위는 생성자 함수를 사용해 객체를 생성하는 방법이고, 아래는 리터럴을 사용하는 방법이다.

 

객체의 프로퍼티(property), 즉 객체의 속성에 대해 알아보겠다. 객체의 프로퍼티는 객체의 중괄호 내부에 들어갈 데이터로, keyvalue의 쌍으로 이루어진 데이터이다. 객체의 프로퍼티는 콜론을 기준으로 왼쪽에는 key 값을, 오른쪽에는 value 값을 작성한다.

let book = {
    title: '자바스크립트 첫걸음',
    author: '김효빈',
    category: '자바스크립트',
};

여기서 title, author, category를 객체의 프로퍼티라고 부른다.

 

객체 프로퍼티의 value는 문자열, undefined, 함수 등 어떠한 자료형을 넣어도 오류가 발생하지 않다.

let car = {
    name: '붕붕',
    model: 'morning',
    color: 'black',
};

// 방법 1
console.log(car.name);
console.log(car.model);
console.log(car.color);

// 방법 2
console.log(car["name"]);
console.log(car["model"]);
console.log(car["color"]);

 

객체의 값들을 꺼내서 사용하는 방법에는 점 표기법과 괄호 표기법이 있다. 위 코드에서 방법 1이 점표기법이고 방법 2가 괄호 표기법이다. 괄호 표기법을 사용할 때에는, 이렇게 대괄호 안에 큰따옴표 혹은 작은따옴표를 사용해 key 값이 문자열임을 명시해야 한다. 코드 실행 결과 대괄호 안의 key 값에 해당하는 value 값들이 알맞게 출력되는 것을 볼 수 있다. 보통 객체 프로퍼티의 값을 꺼내 사용할 때는 점 표기법을 많이 사용하지만, 객체의 key 값이 고정적이지 않고, 특정 함수의 매개변수에 따라 key 값을 계속해서 변경하는 경우에는 괄호 표기법을 활용한다.

 

동일한 car 객체의 프로퍼티 값을 출력하는 getValue 함수를 작성해보겠다.

let car = {
    name: '붕붕',
    model: 'morning',
    color: 'black',
};

const getValue = (key) => {
    console.log(car[key]);
};

getValue('name');

괄호 표기법은 이렇게 객체의 key 값을 특정 함수의 매개변수가 결정하는 상황, 혹은 key 값이 계속 변화하는 상황에 자주 사용된다.

 

3.1 객체 프로퍼티 추가

let cat = {
    age: 2,
};

cat.name = '야옹이';
cat['color'] = 'white';

객체의 프로퍼티를 추가할 때도 객체 프로퍼티의 값을 사용하는 방법과 마찬가지로 점 표기법과 괄호 표기법을 사용한다. 작성했던 객체를 지운 다음, 새로운 cat 객체를 생성하고, cat 객체에 점 표기법으로 name 프로퍼티를 추가하고, 괄호 표기법으로 color 프로퍼티를 추가하였다. 수정 또한 동일하게 작성한다.

 

위의 코드에서 cat 객체는 let 키워드로 선언되어 있는 것을 알 수 있다. 앞의 글서 const 키워드로 선언된 상수는 중간에 값을 변경할 수 없고 let으로 선언된 변수는 중간에 값을 변경할 수 있다고 배웠지만, 객체는 const 키워드로 선언하더라도 프로퍼티의 값은 수정할 수 있다.

 

객체는 생성될 때 고유한 id 값을 갖는다. cat 객체의 프로퍼티를 변경하는 것은, 이 객체의 고유 id 값을 변경하는 것이 아니기 때문에 const 키워드로 선언하더라도 프로퍼티의 값을 변경할 수 있다. 그럼, 객체의 고유한 id 값까지 변경하는 경우는 어떠한 경우가 있는지 다음 코드를 통해 살펴보자.

const cat = {
	name: '야옹이',
	name: '야옹이',
    	age: 2,
	color: 'white'
};

cat = {
	age: 3,
}

const 키워드로 선언된 cat 객체 아래에 key 값은 age, value는 3인 프로퍼티가 저장된 cat객체를 한 번 더 작성했다. 이렇게 cat라는 객체 자체에 새로운 프로퍼티를 저장하려고 하면 이것은 객체의 고유한 id를 변경하는 것이므로 에러가 발생한다.

 

 

3.2 객체 프로퍼티 삭제

프로퍼티를 삭제할 때는 delete 키워드를 사용한다.

delete cat.color;
delete cat['age'];

 

 

3.3 객체의 함수 프로퍼티

const person = {
    name: '홍길동',
    age: 20,
    print: function () {
        console.log('hello world');
    },
    hello: function () {
    console.log(`제 이름은 ${this.name}입니다.`);
    },
};

person.print();
person['print']();

객체의 메서드에서는 this 키워드를 사용해 자신이 속해 있는 객체를 가리킬 수 있다. this 키워드가 person 객체를 가리키기 때문에 this.namekey 값이 name인 프로퍼티의 값이 할당되어 메서드를 호출한 결과, ‘제 이름은 홍길동입니다.’가 출력된다. 메서드를 생성할 때는 화살표 함수보다는 함수 선언식으로 생성하는 것이 좋다.

 

4. 배열

객체가 한 번에 서로 연관된 여러 데이터의 값을 저장할 수 있는 자료형이였다면, 배열은 순서가 있는 요소들의 집합, 여러 개의 데이터가 모여있는 리스트라고 할 수 있다. 배열은 객체와 동일하게 생성자 함수나 리터럴을 사용하여 생성할 수 있다. 먼저 생성자 함수를 이용해 보겠다.

let arr1 = new Array(1, 2, 3);
let arr2 = new Array(3);

console.log(arr1);
console.log(arr2);

코드를 실행하면, arr1 배열에는 괄호 안의 모든 요소가 순서대로 배열에 담기는 반면, arr2 배열은 3이라는 값이 배열의 요소에 할당되는 것이 아니라 undefined라는 3개의 값이 배열에 할당되어 길이가 3인 배열이 생성되는 것을 볼 수 있다. 이렇게 배열 생성자에 값을 할당할 때, 특정 값을 요소에 할당하기 위해서는 생성자 함수의 괄호 안에 여러 개의 값을 넣고, 원하는 크기의 공간을 특정 배열에 할당하기 위해서는 원하는 공간의 크기를 괄호 안에 작성한다.

 

이제 리터럴을 사용해보겠다.

let arr1 = [1, 2, 3];
let arr2 = [3];

console.log(arr1);
console.log(arr2);

코드를 실행하면 arr1 배열은 배열 생성자에 여러 개의 값을 넣은 결과와 동일하게, 배열 안에 숫자 1, 2, 3이 순서대로 담겨 있지만, arr2 배열은 3개의 undefined 값이 할당된 배열이 아닌, 숫자 3이 담겨 있는 배열이 출력되는 것을 볼 수 있다. 이처럼 배열 리터럴을 사용해 배열을 생성하고 배열에 특정 값을 넣으면, 그 값이 순서대로 배열의 요소로 저장한다. 

 

이러한 배열의 요소는 객체 프로퍼티의 값과 마찬가지로, 자료형에 상관없이 작성할 수 있다.

 

4.1 배열 요소 접근

let arr = [1, 'hello', null];

console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);

다음과 같이 배열의 인덱스는 1번부터 시작되지 않고 0번부터 시작된다.

 

4.2 배열 요소 추가

배열 메서드 설명
push() 배열의 마지막 인덱스에 요소 추가
unshift() 배열의 첫 번째 인덱스에 요소 추가

fruits.push('grape')처럼 사용

 

4.3 배열 요소 수정

let animal = ['cat', 'dog', 'hamster'];
animal = ['cat', 'rabbit', 'hamster'];
animal[2] = 'parrot';

console.log(animal);

이 코드는 다음과 같이 출력된다.

 

 

4.4 배열 요소 삭제

배열 메서드
설명
pop()
배열의 마지막 요소 삭제
shift()
배열의 첫 번째 요소 삭제
splice()
배열에서 특정 인덱스의 요소 삭제

 

let colors = ['purple', 'skyblue', 'green', 'yellow', 'orange'];
colors.splice(1, 3);

console.log(colors);

splice 메서드에 1과 3을 인수로 전달해 colors 배열의 1번째 인덱스인 skyblue 부터, 3번째 인덱스인 yellow까지 3개의 요소를 삭제하는 코드를 작성해보았다. 코드를 실행하면, colors 배열의 0번째 인덱스인 purple과 4번째 인덱스인 orange만 출력되는 것을 볼 수 있다.

 

배열의 길이는 console.log(colors.length);를 사용한다.

 

5. 생성자 함수

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayHi = function () {
        console.log('안녕하세요!' + this.name + '입니다');
    };
}

const person1 = new Person('홍길동', 30, 'Manager');
const person2 = new Person('김철수', 25, 'Designer');

console.log(person1.name);
console.log(person2.age);
person1.greet();
person2.greet();

 

생성자 함수와 인스턴스를 사용하면, 이러게 동일한 구조를 갖는 여러 객체를 쉽게 생성할 수 있고, 코드의 재사용성을 높여주며, 반복되는 코드를 줄일 수 있다는 장점이 있다.

 

6. 반복문

6.1 for문

우선 간단한 for문의 형태를 먼저 보여주겠다.

for (let i = 1; i < 6; i++) {
    console.log(i);
}

 

6.2 while문

let i = 1;

while (i <= 10) {
    console.log(i);
    i++;
}

for문과 while문 둘다 다른 언어와 유사하기 때문에 자세한 설명은 안하겠다.

 

6.3 배열과 반복문

이러한 for문과 while문은 자바스크립트에서 배열의 모든 요소들에 접근해야 할 때 유용하게 사용된다.

let arr = [1, 2, 3, 4, 5];

for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}

배열 인덱스는 0번부터 시작하므로, for문 안의 변수 i는 0으로 초기화한다. 그 다음, 배열의 length 프로퍼티는 배열의 현재 길이를 가지고 있기 때문에, for문의 조건식 부분에 arr.length 를 통해 정확하게 배열의 크기만큼 for문을 실행시킬 수 있고, 0부터 1씩 증가하는 i 변수로, 이렇게 배열의 인덱스를 하나씩 늘려가면서 모든 배열의 요소에 접근할 수 있게 된다.

 

6.4 객체와 반복문

 

let person = {
    name: "홍길동",
    age: 25,
    height: 180,
};

console.log(person);
//{name: "홍길동", age: 25, height: 180}
이 person 객체를 배열로 변경하는 3가지 방법이 있다. 우선 첫 번째 방법은 Object.keys() 를 사용하는 방법이다. Object.keys는, 자바스크립트의 Object라는 객체의 메서드로, 매개변수로 받은 객체의 key 들을 모두 찾아 배열의 형태로 반환하는 객체 매서드이다.

 

let newArray = Object.keys(person);
// person 객체를 [key, key] 형태의 배열로 변환
//["name", "age", "height"]

for (let i = 0; i < newArray.length; i++) {
    let nowKey = newArray[i]; // newArray 배열의 요소 순서대로 접근
    console.log(`key : ${nowKey}, value : ${person[nowKey]}`);
}

 

두번째 방법인 Object.values() 메서드는 매개변수로 객체를 넘기면, 해당 객체의 values를 모두 찾아 배열로 반환한다.

let newArray = Object.values(person);
// person 객체를 [value, value] 형태의 배열로 변환

for (let i = 0; i < newArray.length; i++) {
    console.log(`value : ${newArray[i]}`);
}

실행 결과, person 객체의 프로퍼티의 값들이 출력된다.

 

객체를 배열로 변경하는 마지막 방법은 Object.entries() 를 사용하는 것이다. entries 메서드는 객체를 받으면 [[key, value], [key, value]] 형태의 배열로 변환한다.

let newArray = Object.entries(person);
// person 객체를 [[key,value], [key,value]] 형태의 배열로 변환

for (let i = 0; i < newArray.length; i++) {
    console.log(`key : ${newArray[i][0]}, value : ${newArray[i][1]}`);
}

코드를 실행시켜보면, person 객체 프로퍼티의 key와 value 들이 잘 출력되는 것을 볼 수 있다.

 

6.5 for of, for in 반복문

먼저 for...of라는 반복문에 대해 살펴보자. for...of 문은 주로 배열의 모든 요소에 접근해야 될 때 사용된다.
let arr = [1, 2, 3, 4, 5];

for (let i of arr) {
    console.log(i);
}

코드를 실행시켜보면 arr 배열안에 있는 요소들이 순서대로 출력된다.

 

다음으로는, for...in 이라는 반복문에 대해 알아보자. for...in문은 주로 객체에서 사용되며, for문과는 달리 객체의 모든 프로퍼티를 바로 순회할 수 있도록 해준다.
let person = {
    name: "홍길동",
    age: 25,
    height: 180,
};

for (let key in person) {
    console.log(`${key} : ${person[key]}`);
}

출력 결과 person 객체 프로퍼티의 key값과 그에 맞는 value 가 알맞게 출력된 것을 볼 수 있다. 이렇게 for...in 문을 사용하면, 객체를 배열로 변환하는 과정 없이 한 번에 객체의 모든 프로퍼티에 접근할 수 있다.

 

7. 배열 메서드

7.1 forEach

forEach 메서드에는 매개변수로 함수를 전달 할 수 있는데, 이 함수를 매개변수로 전달하는 개념을 콜백 함수라고 설명했었다. 이 콜백함수에는 3가지의 매개변수를 전달 할 수 있는데, 먼저 current value 즉, 처리할 현재 요소를 매개변수로 넣어주겠다.

let arr = [1, 2, 3, 4, 5];

arr.forEach((elm) => {
    console.log(elm);
});

이렇게 elm 이라는 처리할 현재 요소를 매개변수로 넣어준 다음 console.log 로 elm 을 출력하게 되면, 오른쪽 콘솔 탭에 배열 arr 의 요소들이 순서대로 출력되는 것을 볼 수 있다. 이어서 콜백함수의 매개변수로 전달 할 수 있는 또 다른 값인, 실제 배열 요소의 순서를 나타내는 index 를 전달해보겠다.

let arr = [1, 2, 3, 4, 5];

arr.forEach((elm, idx, array) => {
    console.log(`${idx} 번째 요소는 ${elm} 입니다.`);
    console.log(array)
});

이 index 매개변수는 선택적 매개변수로, 첫 번째 매개변수의 옆에 두 번째 매개변수로 작성한다.  매개변수 idx를 이용해 console.log에 “idx 번째 요소는 elm 입니다” 라는 문장을 출력해보면, 배열 요소의 index 번호와 그에 해당하는 elm 이 알맞게 출력되는 것을 볼 수 있다. 마지막으로 이 콜백함수에 넘겨줄 수 있는 매개변수는 array이다.

 

array 매개변수는 콜백함수의 세 번째 매개변수로 작성되며 출력결과 실제 arr 배열 그 자체가 출력되는 것을 확인할 수 있다. 이렇게 콜백함수의 세 번째 매개변수는 배열 요소의 수 만큼 동일한 배열을 출력하는 매개변수이다.

 

7.2 map

배열 메서드 map 을 설명하기 위해 arr 라는 배열의 모든 요소에 10을 곱해서 새로운 배열을 만드는 코드를 작성해보겠다.

let arr = [1, 2, 3, 4, 5];
let newArray = [];

for (let i = 0; i < arr.length; i++) {
    newArray.push(arr[i] * 10);
}
console.log(newArray);

이러한 코드는 map 을 이용하면, 훨씬 짧은 코드로 구현이 가능하다.

let arr = [1, 2, 3, 4, 5];

let newArray = arr.map((elm) => {
    return elm * 10;
});
console.log(newArray);

 

newArray 를 출력해보면, 실제로 이렇게 arr 배열 요소의 값에 10을 곱한 값이 담긴 새로운 배열이 출력되는 것을 볼 수 있다. 이 map 이라는 내장함수는 전달한 콜백함수를 호출한 결과를 모아서 새로운 배열로 반환해주는 내장함수, 배열의 모든요소에 연산을 적용하고, 그 결과를 새로운 배열로 돌려받을 수 있다. 내장함수 map 의 콜백함수에는 forEach와 동일하게 3가지의 매개변수를 전달할 수 있다.

 

7.3 at

배열에서 특정 요소를 찾는 함수에 대해 알아보도록 하겠다.

let colors = ["green", "blue", "purple"];
console.log(colors.at(1)); //blue
console.log(colors.at(-1)); //purple

at이라는 내장함수는 대괄호 안에 인덱스를 작성하는 방법과 동일하게, 매개변수로 배열의 인덱스를 넘겨주면 그 매개변수에 해당하는 인덱스의 배열요소가 출력된다. 하지만 이 매개변수로 -1 이라는 값을 넘겨주면 항상 배열의 마지막 요소의 값을 반환하는 내장함수이다. 이렇게 at 메서드를 사용하면, 배열의 맨 마지막에 위치한 값을 알아야 할 때 훨씬 간편하게 작성할 수 있다.

 

7.4 includes

includes 메서드는 매개변수로 받은 요소를 배열이 포함하고 있는지 판별하여 boolean 값으로 반환한다.

let colors = ["green", "blue", "purple"];
console.log(colors.includes("blue")); // true
console.log(colors.includes("yellow")); // false

 

includes 메서드는 매개변수로 또 다른 값을 전달할 수 있다. 우리가 찾을 배열 요소의 값이 적힌 매개변수 옆에 배열의 인덱스를 작성할 수 있다. blue 라는 매개변수의 오른쪽에 매개변수로 각각 2와 1을 전달한 값을 출력해보겠다.

 

 
let colors = ["green", "blue", "purple"];
console.log(colors.includes("blue", 2)); // false
console.log(colors.includes("blue", 1)); // true

이렇게 includes 메서드는 배열의 요소 중 특정값이 존재하는지를 쉽게 확인할 수 있는 메서드이다.

 

7.5 indexOf

indexOf 메서드는 특정 값이 배열 요소에 있는지를 검사하는 것이 아니라, 특정 값을 지닌 요소가 몇 번째에 위치하는 요소인지를 찾아주는 함수이다.

let colors = ["green", "blue", "purple"];
console.log(colors.indexOf("purple"));// 2
console.log(colors.indexOf("yellow")); // -1

purple 이라는 값의 요소는 colors 배열의 2번째 인덱스에 있으므로, 출력 결과 2 가 출력이 되고, colors 배열에 존재하지 않는 값인 yellow라는 값은 -1이 출력됨을 알 수 있다. indexOf 메서드도 includes 메서드와 마찬가지로 두 번째 매개변수로 검색을 시작할 인덱스를 전달 할 수 있다.

 

7.6 findIndex

indexOf는 특정 요소가 배열의 몇 번째 index 인지를 찾아주는 함수지만, indexOf 메서드는 배열 요소의 값이 객체형태거나, 배열의 형태일 때의 인덱스를 찾아주지는 못한다. findIndex 내장함수를 사용해 color 값이 purple인 배열 요소를 찾아보다.

let colors = [
    { id: 1, color: "green" },
    { id: 2, color: "blue" },
    { id: 3, color: "purple" }
];

let idx = colors.findIndex((elm) => elm.color === "purple");

console.log(idx); // 2

이렇게 배열 요소의 값이 객체 형태라면, color 가 purple 인 객체가 배열의 몇 번째인지 찾기 위해서는 indexOf 가 아닌, findeIndex 함수를 사용해야한다. findIndex 또한 콜백함수를 작성해주고, 콜백함수의 매개변수로 elm 이라는 current value 를 전달한다. findIndex 내장함수 또한 매개변수로 current value와 index, array 를 전달할 수 있다.

 

7.7 find

find 함수는 찾아낸 값의 인덱스를 반환하는 것이 아니라, 찾아낸 값 그 자체를 반환하는 함수이다.

let colors = [
    { id: 1, color: "green" },
    { id: 2, color: "blue" },
    { id: 3, color: "purple" }
];

let idx = colors.find((elm) => elm.color === "purple");

console.log(idx); // { id: 3, color: "purple" }

find 메서드 또한 마찬가지로 콜백함수의 매개변수로 current value와 index, array 를 전달할 수 있고, 이 find 메서드는 이렇게 주어진 조건을 만족하는 첫 번째 배열 요소의 값을 반환하고, 만약 배열 요소에 해당 값이 없다면, undefined 라는 값을 반환하는 내장함수이다.

 

7.8 filter

이번에는 특정 배열에서 원하는 요소들을 추출할 수 있는 메서드에 대해 배워보도록 하겠다. 먼저 배열에서 특정 조건을 만족하는 값들만 따로 추출하여 새로운 배열을 생성하는 filter 함수에 대해 알아보자.
let colors = [
    { id: 1, color: "green" },
    { id: 2, color: "blue" },
    { id: 3, color: "purple" }
];

let filterArray = colors.filter((elm, idx, array) => elm.id > 1);
console.log(filterArray);

이렇게 filterArray 를 출력해보면, { id: 2, color: "blue" } 와 { id: 3, color: "purple" } 값이 담긴 배열이 출력되는 것을 볼 수 있다. filterArray는 조건을 만족하는 가장 첫 번째 값만 반환하는 것이 아니라, 조건을 만족하는 모든 값들을 새로운 배열에 담아 반환하는 내장함수이다.

 

7.9 slice

slice 메서드는 두 개의 매개변수로, begin과 end를 전달 받는다. 전달받은 매개변수로 begin부터 end보다 1 작은 인덱스의 요소까지 배열을 복사하여 새로운 배열 객체로 반환한다.

let colors = [
    { id: 1, color: "green" },
    { id: 2, color: "blue" },
    { id: 3, color: "purple" },
    { id: 4, color: "yellow" }
];

let sliceArray = colors.slice(1, 3);
console.log(sliceArray);
코드를 실행하면 sliceArray 배열에는 { id: 2, color: "blue" } 와 { id: 3, color: "purple" } 값이 담겨있는 것을 볼 수 있다.
 

7.10 concat

두개의 배열을 이어 붙일 수 있는 메서드이다.

let array1 = ["green", "blue"];
let array2 = ["purple", "yellow"];

console.log(array1.concat(array2));

코드를 실행하면, 이 array1과 array2 배열이 하나의 새로운 배열로 합쳐진 것을 볼 수 있다. 이렇게 concat 메서드를 사용하면 두 개의 배열을 하나로 합쳐 새로운 배열로 반환할 수 있다.

 

 

7.11 join

concat과 다르게 join 메서드는 하나의 배열에서 배열 요소들의 값들을 문자열로 이어주는 메서드이다.

let colors = ["green", "blue", "purple"];

console.log(colors.join());
console.log(colors.join(" "));

join 메서드 내부에 들어가는 매개변수는 구분자로, 요소들을 합칠 때 사이에 어떤 문자를 넣을 것인지 결정할 수 있다. join 메서드에 아무런 매개변수를 넣어주지 않으면 쉼표가 기본적으로 구분자로 출력되게 된다.

 

7.12 sort

배열을 정렬할 때 사용하는 내장함수이다.

let colors = ["green", "blue", "purple"];
colors.sort();

console.log(colors);

sort 를 사용한 다음 colors 배열을 출력해보면, colors 배열의 요소들이 알파벳 순으로 정렬된 것을 확인할 수 있다.

이 배열을 내림차순으로 정렬하기 위해서는 compare라는 이름의 함수를 써야한다. 코드를 먼저 보겠다.

 

const compare = (a, b) => {
    if (a > b) return -1;
    else if (a < b) return 1;
    else return 0;
};

let colors = ["green", "blue", "purple"];
colors.sort(compare);

console.log(colors);

compare 함수는 a와 b, 2개의 매개변수를 전달받도록 해준다. 여기서 a는 배열의 다음 요소를, b는 배열의 이전 요소를 의미하고, a가 b보다 클 때, b가 a보다 클 때, 그리고 그외 이렇게 3가지 조건으로 나눠서 작성한 코드이다.

 

이 반환 값들이 뜻하는 것은, 반환 값이 -1 이라면 다음 요소의 값인 a가 이전 요소의 값인 b 보다 앞에 있어야 하고, 1이라면 b가 a 보다 앞에 있어야하며 반환값이 0이라면, a와 b의 순서를 바꾸지 않는다 라는 의미이다.

 

우리는 배열 요소를 내림차순으로 정렬해야하므로, 이전 값이 다음 값보다 커야하기 때문에 다음 요소인 a의 값이, 이전 요소인 b의 값 보다 크다면 -1을 반환해 a가 b보다 앞에 있어야한다고 알려주도록 한다. 따라서 마찬가지로 a가 b 보다 작다 라는 조건식에는 1을 반환해주고, 그 외의 경우에는 0을 반환한다.

 

이번에는 문자가 아닌 숫자가 담긴 배열을 정렬해보겠다.

let numbers = [1, 100, 25, 50, 120, 3];
numbers.sort();

console.log(numbers); // [1, 100, 120, 25, 3, 50]

numbers 배열을 sort 메서드를 이용해 정렬을 하면, 숫자의 크기 순서가 아닌 사전순으로 정렬이 된다.

 

const compare = (a, b) => {
    //오름차순
    return a - b;
};

let numbers = [1, 100, 25, 50, 120, 3];

numbers.sort(compare);
console.log(numbers); // [1, 3, 25, 50, 100, 120]

앞에서 배웠던 것처럼 이 compare 함수는 0보다 작은 값이 반환되면, 이전 요소와 다음 요소의 위치를 바꾸기 때문에, 다음 요소에서 이전 요소를 뺀 값이 0보다 커야하므로 다음 요소인 a 에서 이전 요소인 b를 뺀 값이 음수라면, 순서를 바꾸도록 a-b 의 값을 반환한다. 반대로 내림차순으로 정렬하기 위해서는 reutn b - a;를 사용하면 된다.

 

7.13 reduce

배열의 각 요소에 대해 함수를 실행하고 누적된 값을 출력할 때 유용하게 사용되는 내장 함수이다. reduce 메서드는 콜백함수와 initialValue라는 초기값을 전달하고, 이 콜백함수의 매개변수로는 accumulator, currentValue, currentIndex 가 있다. accumulator(acc)는 콜백함수의 반환값을 누적하는 매개변수이고, cur이라는 매개변수는 우리가 계속 사용했었던 currentValue 즉, 처리할 현재 요소의 값을 나타내고, 매개변수 currentIndex(idx)는 처리할 현재 배열 요소의 인덱스를 나타낸다.

 

let numbers = [1, 100, 25, 50];

let sum = numbers.reduce((acc, cur, idx) => {
    console.log(acc, cur, idx);
    return acc + cur;
}, 0); // 여기서 0은 초기값 나타냄

console.log(sum);//176

코드를 실행하면 0 1 0, 1 100 1, 101 25 2, 126 50 3이 출력(3개씩 끊어서 생각)되고, sum 변수는 176 이라는 값이 출력된다.

 

7.14 isArray

전달된 매개변수가 배열인지 아닌지를 판별하는 내장함수이다.

console.log(Array.isArray([1, 100, 50, 3])); // true
console.logArray.isArray({ id: 3, color: "purple" })); // false
console.logArray.isArray("string")); // false
console.logArray.isArray(undefined)); // false

 

 

8. 배열과 객체 구조 분해 할당

8.1 배열의 구조 분해 할당

구조 분해 할당이란 배열이나 객체의 요소 및 프로퍼티들을 분해해서 그 값들을 각각의 변수에 할당하는 자바스크립트의 표현식이다. 배열의 구조 분해 할당은, colors 배열의 요소들을 분해한 다음, 그 값들을 순서대로 각각의 새로운 변수에 할당할 수 있는 방법으로, 대괄호 안에 변수들을 선언하고 할당할 배열의 이름인 colors를 작성해 배열의 요소들을 할당해준다.

let colors = ["green", "blue", "purple"];
let [c1, c2, c3] = colors;

console.log(c1); // "green"
console.log(c2); // "blue"
console.log(c3); // "purple"

 

이번에는 c1, c2, c3 변수를 한번에 선언하고, colors라는 배열을 별도로 선언하지 않고, 이 변수들에 배열의 값을 바로 할당해주도록하겠다.

let c1, c2, c3;
[c1, c2, c3] = ["green", "blue", "purple"];

console.log(c1); // "green"
console.log(c2); // "blue"
console.log(c3); // "purple"

이렇게 변수의 선언을 분리해서 배열의 값을 할당하는 방법을 우리는 "선언 분리 할당" 이라고 부른다. 이번엔 배열의 길이보다 더 많은 수의 변수에 값을 할당해보면,

let c1, c2, c3, c4;
[c1, c2, c3, c4] = ["green", "blue", "purple"];

console.log(c1); // "green"
console.log(c2); // "blue"
console.log(c3); // "purple"
console.log(c4); // undefined

만약 남은 변수들에 undefined라는 값이 할당되는 것을 원하지 않는다면, 우리는 해당 변수에 기본값을 지정해 줄 수 있다. 이는 다음과 같이 나타낼 수 있다.

[c1, c2, c3, c4 = "yellow"] = ["green", "blue", "purple"];

출력 결과, c4에는 undefined가 아닌, yellow 라는 값이 할당 된 것을 확인할 수 있다.

 

우리는 흔히 두 변수의 값을 변경하기 위해서는, tmp 와 같은 임시 변수가 필요하지만, 구조분해를 이용하면, 임시 변수 없이 두 변수의 값을 교환할 수 있다. 우리가 작성했던 코드처럼, 왼쪽에는 값을 할당 할 변수를, 오른쪽에는 교환할 값의 변수를 작성하면,

let a = 10;
let b = 5;

[a, b] = [b, a];

console.log(a); // 5
console.log(b); // 10

다음과 같이 쓸 수 있다.

 

8.2 객체의 구조 분해 할당

let colors = {
    c1: "green",
    c2: "blue",
    c3: "purple",
};

let { c1, c2, c3 } = colors;

console.log(c1);// green
console.log(c2);// blue
console.log(c3);// purple

객체의 구조 분해 할당은 대괄호가 아닌, 중괄호를 사용한다. 배열 구조 분해 할당과 동일하게 중괄호안에 변수들을 작성하고, 오른쪽에는 분해 할 객체의 이름을 작성해보았다.

 

이번에는 이 c1, c2, c3이라는 key값을 변수의 이름으로 사용하지 않고, 다른 이름을 갖는 변수에 값을 할당하는 방법을 알려주겠다.

let colors = {
    c1: "green",
    c2: "blue",
    c3: "purple",
};

let { c1: color1, c2: color2, c3: color3 } = colors;

console.log(color1); //green
console.log(color2); //blue
console.log(color3); //purple

이렇게 객체 프로퍼티의 값을 할당할 변수가 객체 프로퍼티의 key값과 다를 경우에는 :(클론)을 이용해, 다른 이름의 변수에 값을 할당할 수 있다. 이렇게 객체 프로퍼티의 key값의 오른쪽에 클론을 작성하고, 다른 이름의 변수를 작성한다.

 

객체의 구조 분해 할당 또한 배열의 구조 분해 할당과 같이, 변수의 수가 객체 프로퍼티의 수보다 클 경우, undefined가 할당되는 변수에 기본값을 설정할 수 있다.

let { c1, c2, c3, c4 = "yellow" } = colors;

 

 

9.spread와 rest

9.1 spread

const blueToy = {
    type: "bear",
    price: 15000,
    color: "blue",
};

const yellowToy = {
    type: "bear",
    price: 15000,
    color: "yellow",
};

작성한 객체들을 살펴보면, 새로 추가한 객체들과 toy 객체의 프로퍼티 중 type과 price값이 동일한 것을 볼 수 있다. 이렇게 비슷한 프로퍼티를 가진 객체를 생성하려면, 동일한 코드를 여러번 작성해야하는 번거로운 작업을 해야한다. 이와 같은 상황에서 spread 문법을 사용할 수 있다. spread는 '...' 기호로 표기한다.

 

const toy = {
    type: "bear",
    price: 15000,
};

const blueToy = {
    ...toy,
    color: "blue",
};

const yellowToy = {
    ...toy,
    color: "yellow",
};

console.log(blueToy);
console.log(yellowToy);


이는 배열에서도 사용가능하다.

const color1 = ["red", "orange", "yellow"];
const color2 = ["blue", "navy", "purple"];

const rainbow = [...color1, "green", ...color2];

console.log(rainbow);

 

9.2 rest

rest는 "나머지 매개변수" 라고도 하며, rest 문법 또한 ... 기호를 사용하기 때문에 spread 와 비슷해보이지만, 이 둘은 서로 다른 역할을 하는 문법이다. spread는 객체나 배열에서 반복적인 값들을 퍼트려주는 문법이지만, rest 는 이와 반대로 특정 부분들을 하나의 배열이나 객체로 묶는 문법이다. 

 

const blueToy = {
    type: "bear",
    price: 15000,
    color: "blue",
};

const { type, ...rest } = blueToy;

console.log(type);
console.log(rest);

출력 결과, rest 변수는 객체의 형태로 출력되고, 객체 안에는 blueToy 객체 프로퍼티 중 type 값을 제외한 나머지 값들이 들어있는 것을 볼 수 있다. 이렇게 rest는 구조 분해 할당을 통해 원하는 값들을 꺼내고 나머지 값을 별도로 묶어서 할당할 수 있다. 이 또한 배열에서 사용가능하다.

 

const color = ["red", "orange", "yellow", "green"];
const [c1, c2, ...rest] = color;

console.log(c1);
console.log(c2);
console.log(rest);

코드를 실행하면, rest에는 배열이, c1과 c2에는 color 배열의 0 번째, 1번째 요소가 할당된 것을 확인할 수 있다.

 

이러한 rest와 spread 문법은 함수에서 유용하게 사용된다.

const print = (a, b, ...rest) => {
    console.log(a);
    console.log(b);
    console.log(rest);
};

print(1, 2, 3, 4, 5, 6);

출력 결과를 보면, a와 b 에는 각각 1과 2의 값이 할당되었고, rest에는 1과 2를 제외한 나머지 값인 [3, 4, 5, 6] 이 할당되었다. 이렇게 함수의 매개변수에 rest를 사용하게 되면, rest에는 함수에서 받아온 매개변수들로 이루어진 배열이 할당된다.

 

const print = (...rest) => { // rest
    console.log(rest);
};

const numbers = [1, 2, 3, 4, 5, 6];
print(...numbers); // spread

→ 출력결과: [1, 2, 3, 4, 5, 6]

'프론트' 카테고리의 다른 글

[JS] DOM과 DOM API  (0) 2025.07.01
[JS] 비동기와 API  (2) 2025.06.25
[JS] 자바스크립트 기초(1)  (0) 2025.05.01
CSS 기초  (1) 2025.04.29
HTML 기초  (1) 2025.04.04