프론트엔드/React

리액트에서 자주 사용하는 기초 JS 정리

장쫑이이 2024. 8. 9. 17:49

 

 

 

배열의 주요 메서드

map

💡 원본 배열에서 각 요소를 가공한 새로운 배열을 리턴하는 함수

 

1. 배열 내 모든 요소 각각에 대해

2. 주어진 함수를 호출한 결과를 모아

3. 새로운 배열을 반환

 

* 원본을 바꾸지 않고 새로운 배열을 반환한다는 것이 중요!!  > 무조건 return 써주기!! (안쓰면 undefined가 출력됨)

 

예시 코드

const numbers = [1, 2, 3, 4, 5];
const squared = numbers.map(function (num) {
  return num * num;
});

console. log (squared);
// [1, 4, 9, 16, 25] 출력

 

 

 

filter

주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환

 

예시 코드

const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers);  // [2, 4]
const movieList = [
  {
    id: 1,
    title: "movie01",
    img: "img01.jpg",
  },
    { id: 2, title: "movie02", img: "img02.jpg" },
    { id: 3, title: "movie03", img: "img03.jpg" },
    { id: 4, title: "movie02", img: "img04.jpg" },        
];

const filterdMovieList = movieList.filter(function(movie) {
  return movie.title === "movie02";
});

//  movie02를 가진 두 객체가 배열에 들어가게 됨
//  [ 
//    { id: 2, title: "movie02", img: "img02.jpg" },
//    { id: 4, title: "movie02", img: "img04.jpg" }, 
//  ]

 

 

reduce

배열의 각 요소에 대해 주어진 함수를 실행하고 결과물을 누적시켜 반환 = 누적기

 

예시 코드

const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum);  // 15

 

 

sort

배열의 요소를 적절한 위치에 정렬하고 배열을 반환

원본 배열 자체를 바꾸기 때문에 불변성이 바뀜

기본적으로 문자로 계산하기 때문에 숫자도 기본 옵션이 없다면 문자화 시켜서 변환됨.

 

예시 코드

// 기본 사용법
const fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();
console.log(fruits);  // ["Apple", "Banana", "Mango", "Orange"]

// 숫자 배열 정렬
const numbers = [40, 100, 1, 5, 25];
numbers.sort((a, b) => a - b);
console.log(numbers);  // [1, 5, 25, 40, 100]

// 숫자를 그냥 정렬하면 문자화로 인해 순서가 이상해짐
const numbers = [40, 100, 1, 5, 25];
numbers.sort();
console.log(numbers);  // [1, 100, 25, 40, 5]

 

 

 


 

 

 

Destructuring

객체나 배열의 속성을 보다 쉽게 추출할 수 있는 문법

 

객체의 Destructuring

여기가 배열보다 중요!

 

1-1. 다중 속성 추출

const { name, price } = item;
console.log(name);  // 커피
console.log(price); // 4000

 

1-2. 함수 매개변수에서의 사용

리액트 컴포넌트에서 많이 사용

obj 안에 key를 그대로 사용하여 분해한다는 것도 중요한 개념

function greet({ name, age }) {
  console.log(`안녕하세요, 제 이름은 ${name}이고 나이는 ${age}살입니다.`);
}
greet({ name: "르순이", age: 28 });

 

 

배열의 Destructuring

let colors = ["red", "green", "blue"];
let [firstColor, secondColor] = colors;
console.log(firstColor);  // red
console.log(secondColor); // green


let [, , thirdColor] = colors;
console.log(thirdColor);  // blue

 

 

 

 

Spread operators

배열이나 객체를 개별 요소로 확장 (복사하거나 합칠 때) 할 때 사용

불변성이 깨지는 현상이 생김 : 바라보는 주소가 같기 때문

 

1. 객체에서의 사용 (spread operators)

1-1. 객체 복사 및 확장

객체의 속성을 쉽게 다른 객체로 복사하거나 확장

const originalUser = { name: "길동이", age: 28 };
const updatedUser = { ...originalUser, location: "한국" };
console.log(updatedUser);  // { name: "길동이", age: 28, location: "한국" }


// 불변성이 깨짐 (그래서 위와 같이 해야함 얕은복사)
const originalUser2 = { name: "르탄이", age: 28 };
const updatedUser2 = originalUser2
updatedUser2.name = "길순이"

console.log(originalUser2);  // { name: "길순이", age: 28 }
console.log(updatedUser2);  // { name: "길순이", age: 28 }

 

 

2. 배열에서의 사용 (spread operators) 

2-1. 배열 합치기

두 배열을 간편하게 합칠 때 많이 사용

const first = [1, 2, 3];
const second = [4, 5, 6];
const combined = [...first, ...second];
console.log(combined);  // [1, 2, 3, 4, 5, 6]

 

 

 

rest operator

함수의 매개변수에서 사용되거나, 객체 리터럴이나 배열 리터럴에서 남은 부분을 하나의 변수로 그룹화할 때 사용

여러 인수를 배열로 그룹화하거나, 객체 분해 할당에서 특정 속성을 제외한 나머지 속성들을 새 객체로 그룹화할 때 사용

 

1-1. 함수 매개변수

배열로 넣은 적은 없지만 ...에 의해 배열로 들어가게 됨

function sum(...numbers) {
    return numbers.reduce((acc, current) => acc + current, 0);
}

console.log(sum(1, 2, 3, 4)); // 10

 

 

1-2. 객체 분해 할당

const person = {
    name: "John",
    age: 30,
    country: "USA",
    occupation: "Developer"
};

const { country, ...rest } = person;
console.log(rest); // { name: "John", age: 30, occupation: "Developer" }

 

 

 


 

 

논리합 연산자 (||)

좌변이 truthy 값인 경우 결과값을 반환 > 우변은 평가되지 않음

 

논리곱 (&&) 연산자

좌변이 truthy 값인 경우 우변 평가 > 조건에 따라 특정 코드를 실행할때 유용

 

Optional Chaining (?.)

객체의 속성에 접근할때 오류가 아닌 undefined를 반환 > 객체의 중첩된 속성에 안전하게 접근

 

const user = {
    profile: {
        name: "르탄이",
        details: {
            age: 30,
            location: "서울시 강남구"
        }
    }
};

console.log(user.profile?.details?.age); // 출력: 30

 

원래 profile이나 detail 값이 undefined나 null인 경우 에러를 발생하는데 .?를 활용하면 문제 예방 가능

 

Null 병합 연산자 (??)

좌변이 null이나 undefined 일때 우변 평가

// 사용자의 위치 설정이 없으면 기본 위치를 제공
let userLocation = null;
console.log(userLocation ?? 'Unknown location');  // 출력: Unknown location

userLocation = 'Seoul';
console.log(userLocation ?? 'Unknown location');  // 출력: Seoul

// 사용자 입력이 0인 경우에도 0을 유효한 값으로 취급
const temperature = 0;
console.log(temperature ?? 25);  // 출력: 0

 

 

논리 Or 연산자와 null 병합 연산자의 차이

truthy한 값이냐 아니냐 vs null이냐 undefined이냐 아니냐

 


 

 

ES6 Modules 기본

재사용 가능한 코드 조각을 캡슐화
다른 자스 파일에서 쉽게 재사용 가능

 

일반적인 코드

// math.js
export const add = (a, b) => a + b;
export const multiply = (a, b) => a * b;

// app.js
import { add, multiply, ONE, sample } from './math.js';

console.log(add(2, 3)); //5
console.log(multiply(2, 3)); //6

 

 

 

모듈을 사용해야하는 이유

1. 명확한 종속성 관리

기존 <script> 태그를 사용해서 로드하는 방식은 로딩 순서를 수동으로 관리 > 종속성을 추적 관리 어렵고 버그 발생 가능성이 높아짐

 

모듈 시스템을 사용하면 개발자는 파일을 로드하는 순서에 신경 쓸 필요가 없음 (종속성을 내부적으로 선언)

<!-- 전통적인 스크립트 로딩 방식 -->
<script src="jquery.js"></script>
<script src="plugin.js"></script> <!-- 이 스크립트는 jquery.js에 의존 -->
<script src="app.js"></script> <!-- 이 스크립트는 plugin.js와 jquery.js에 의존 -->


// ES6 모듈 사용 예시
import $ from 'jquery';
import plugin from 'plugin'; // 자동으로 jQuery에 대한 의존성을 처리
import app from 'app'; // 모든 의존성이 충족되면 실행

 

 

2. 코드 캡슐화와 충돌 방지

- 모듈은 자체적으로 스코프를 가짐, 모듈 외부에서 모듈 내부의 변수에 직접 접근 할 수 없음 > 전역변수 오염, 이름 충돌 방지

- 여러 스크립트에서 동일한 함수 이름을 사용해도 괜찮아짐

// module1.js
export function conflictFunction() {
  console.log('Module 1의 함수');
}

// module2.js
export function conflictFunction() {
  console.log('Module 2의 함수');
}

// app.js
import { conflictFunction as function1 } from './module1';
import { conflictFunction as function2 } from './module2';

function1(); // "Module 1의 함수"
function2(); // "Module 2의 함수"

 

 

3. 효율적인 코드 로딩

필요한 기능한 선택적으로 불러오기 가능 > 초기 로딩 시간 단축

코드 스플리팅을 사용하면 필요한 코드만 동적으로 로드 가능

// 동적으로 모듈 로드하기 (예: 사용자가 특정 기능을 활성화했을 때)
button.addEventListener('click', event => {
  import('./heavyModule.js')
    .then(module => {
      module.heavyFunction();
    })
    .catch(err => {
      console.error("모듈 로딩에 실패했습니다.", err);
    });
});

 

 

 

이름 바꾸기, 기본 내보내기

별칭사용

import 시 특정 요소에 별칭을 지정하여 충돌을 방지 > 명확성을 높일 수 있음

import { square as sqr } from './utils.js';
console.log(sqr(4));  // 16

 

 

기본 내용 내보내기, 가져오기

모듈당 하나의 주요 기능을 내보낼 때 유용

export default를 통해 내보내진 모듈은 import시 이름변경이 가능
이름 명시하지 않아도 됨

 

// math.js
export default function multiply(x, y) {
  return x * y;
}

// app.js
import multiply from './math.js';
console.log(multiply(6, 7));  // 42
// export default 시 모듈이름 변경은 자유!

// utils.js
export default function square(x) {
  return x * x;
}

// main.js
import mySquare from './utils.js';
console.log(mySquare(4));  // 출력: 16

 

전체 모듈 내용 가져오기

// app.js
import * as MathFunctions from './math.js';

console.log(MathFunctions.add(10, 5));       // 15
console.log(MathFunctions.multiply(10, 5));  // 50

 

 

 


 

 

 

Async/Await

복잡한 프로미스 체인을 간결하고 동기적인 흐름으로 작성할 수 있게 도와줌

 

Promise

비동기 작업의 최종 완료 또는 실패를 나타내는 객체

주로 서버나 데이터를 요청하고 받아오는 HTTP 요청 처리에 사용

.then(), .catch(), finally() 메소드를 이용해 연속적으로 처리 가능 > 콜백 지옥 피하고 코드 가독성을 높임

 

const myPromise = new Promise(function(resolve, reject) {
  // 비동기 작업을 수행하고
  if (/* 작업 성공 */) {
    resolve('Success!');
  } else {
    reject('Error!');
  }
});

myPromise.then(function(value) {
  // 성공(resolve)한 경우 수행
  console.log(value);  // 'Success!'
}).catch(function(error) {
  // 실패(reject)한 경우 수행
  console.error(error);  // 'Error!'
});

 

 

async

promise를 반환

async function fetchData() {
  return 'Data loaded';
}

// 아래 코드와 같아요.
// async function fetchData() {
// 	return Promise.resolve('Data loaded');
// }

fetchData().then(console.log); // 'Data loaded'

 

 

await

프로미스의 완료를 기다리는 동안 함수의 실행을 잠시 중단

프로미스가 해결되면 자동으로 함수의 실행을 재개

> 비동기 코드를 동기적으로 표현이 가능

async function fetchData() {
  try {
    const data = await fetch('https://api.example.com/data');
    const json = await data.json();
    console.log(json);
  } catch (error) {
    console.error("Data loading failed", error);
  }
}

fetchData();