Frontend/JavaScript

[JavaScript] 심화

JOKUN 2024. 6. 10. 11:58



Truthy와 Falsy

자사스크립트에서는 참, 거짓이 아닌 값도 참, 거짓으로 평가함

이를 이용하면 조건문을 간결하게 만들 수 있음 

 

Falsy한 값

let f1 = undefinde;
let f2 = null;
let f3 = 0;
let f4 = -0;
let f5 = NaN;
let f6 = "";
let f7 = 0n;

 

Truthy한 값

7가지의 falsy한 값들을 제외한 나머지 모든 값 

 

활용 사례

function printName(person) {
console.log(person.name);
}

let person;
// person은 undefined 가 됨 
printName(person); // => 오류남

 

아래와 같이 사용하면 조건문을 간결하게 사용할 수 있음 

function printName(person) {
	if(!person){
    console.log("person의 값이 없음");
    return;
    }
	console.log(person.name);
}

 

 


단락 평가(Short-circuit Evaluation)

첫 번째 피연산자의 값만으로도 어떠한 값이 확정지어지면 두번째 값에는 접근하지 않음 

 

함수로 확인해보면 returnFalse함수로만 값이 확정되어서 그 다음인 returnTrue함수는 실행되지 않음 

 

순서를 바꾸면 첫번째 피연산자 값만으로는 값이 확정이 나지않아서 returnFalse함수가 호출됨 

or로 사용한다면 returnTrue함수만으로 값이 확정되기때문에 returnFalse 함수가 실행되지 않음

 

리턴값이 bool 값이 아니어도 사용할 수 있음 (Truthy & Falsy)

 

 

활용 사례

function printName(dog){
	if(!dog){
    console.log("dog에 값이 없음");
    return;
	}
    console.log(dog.name);
}

기존에 작성했던 코드를 아래와 같이 개선이 가능함 

function printName(dog){
const name = dog && dog.name;
console.log(name || "dog 값이 없음");
}

printNamer();
//콘솔 : dog의 값이 없음 

printName({name: "KUN"});
// 콘솔 : KUN
값이 True || True 일 때는 첫번째 값이 반환되고,
True && True 일 때는 마지막 값이 반환 됨

 

 


 

구조 분해 할당

배열이나 객체에 저장된 여러개의 값을 분해해서 각각 다른 변수에 할당하는 문법

 

배열의 구조 분해 할당

ler arr = [1, 2, 3];

let [one, two, three, four] = arr;

console.log(one, two, three, four);
// 콘솔 : 1 2 3 undefined

 

ler arr = [1, 2, 3];

// 기본값 설정도 가능
let [one, two, three, four = 4] = arr;

console.log(one, two, three, four);
// 콘솔 : 1 2 3 4

 

 

객체의 구조 분해 할당

let person = {
name : "조쿤",
age : 4,
hobby : "산책",
}

let {name, age, hobby, extrea = "hello" } = person;
console.log(name, age, hobby);
//콘솔 : 조쿤 4 산책 hello

let {
name, 
age : myAge // 프로퍼티 명 변경
hobby,
extrea = "hello" 
} = person;

 

 

객체 구조 분해 할당을 이용해서 함수의 매개변수를 받는 방법

const func = ({name, age, hobby, extra }) => {
console.log(name, age, hobby, extra);
}

func(person);
// 콘솔 : 조쿤 4 산책 undefined

 

 


 

Spread 연산자와 Rest 매개변수

Spread 연산자

spread : 흩뿌리다, 펼치다 라는 뜻

객체나 배열에 저장된 여러개의 값을 개별로 흩뿌려주는 역할

let arr1 = [1, 2, 3];
let arr2 = [4, ...arr1, 5, 6];

console.log(arr2);
//콘솔 : [4, 1, 2, 3, 5, 6]

let obj1 = {
a: 1,
b: 2,
}

let obj2 = {
...obj1,
c: 3,
d: 4,
}

console.log(obj2);
// 콘솔 : {a: 1, b: 2, c: 3, d:4}

 

function funcA(p1, p2, p3){
console.log(p1, p2, p3);
}

funcA(...arr1);
//콘솔 : 1 2 3

 

 

Rest 매개변수

rest: 나머지 라는 뜻

나머지 매개변수

function funcB(...rest){
console.log(rest);
}

funcB(...arr1);
// 콘솔 : [1, 2, 3]

function funcB(one, ...rest){
console.log(rest);
}
// 콘솔 : [2, 3];
rest 매개변수 뒤에 변수를 추가할 수 없고 rest 매개변수는 항상 뒤에 작성해야한다

 

 


 

원시타입 vs 객체타입 

원시타입과 객체타입으로 두가지로 구분하는 이유?  원시타입과 객체타입은 값이 저장되거나 복사되는 과정이 서로 다르기 때문

 

차이점

  • 원시타입 : 값 자체로써 변수에 저장되고 복사 됨
  • 객체타입 : 참조값을 통해 변수에 저장되고 복사 됨 

 

원시타입

불변값 (메모리 값 수정 X)

원시타입은 한번 메모리에 올라간 값은 변하지않음

 

 

객체타입

가변값 (메모리 값 수정 O)

메모리에 원시타입처럼 값이 아닌 참조값을 저장하게됨 

특정 프로퍼티의 값을 수정하게 되면 메모리에 저장되어있던 원본 데이터를 수정해버림 

 

주의사항

의도치 않게 값이 수정될 수 있음

O1의 값이 변경되지 않고 참조값을 추가해서 사용할 수 있음 

 

 

 

 

객체간의 비교는 기본적으로 참조값을 기준으로 이루어진다

첫번째 콘솔은 true, 두번째는 false 가 나옴 

 

 

 

배열과 함수도 사실 객체이다

 

 


순회 (Iteration)

배열, 객체에 저장된 여러개의 값에 순서대로 하나씩 접근하는 것을 말함

 

배열 인덱스

let arr = [1, 2, 3];

// 배열 인덱스
for (let i = 0; i < arr.length; i++) {
console.log(arr[i];
}
// 콘솔 : 1 2 3

let arr2 = [4, 5, 6, 7, 8];

for(let i = 0; i > arr2.length; i++){
console.log(arr2[i]);
}
//콘솔 : 4 5 6 7 8

 

for of 반복문

for (let item of arr) {
console.log(item);
}
// 콘솔 : 1 2 3

 

객체 순회

Object.keys

let dog = {
name : "조쿤",
age : 4,
hobby : "산책",
}

// Object.keys 사용 -> 객체에서 key 값들만 뽑아서 새로운 배열로 반환함

let keys = Object.keys(dog);
//or

for (let kwy of keys){
//키 밸류 동시 순회
const value = person[key];
console.log(key, value);
}

 

Object.values

let values = Object.values(dog);

for(let value of values){
console.log(value);
}

 

for in

for(let key in dog){
console.log(key);
}
// 콘솔 : name age hobby

for(let key in dog){
const value = dog[key];
console.log(key, value);
}
// 콘솔 : name 조쿤 / age 27 / hobby 산책

 

 


 

 

배열 메서드

요소 조작

push

배열의 맨 뒤에 새로운 요소를 추가하는 메서드

let arr = [1, 2, 3];

arr1.push(4, 5, 6);
console.log(arr1);
// 콘솔 : [1, 2, 3, 4, 5, 6]

 

 

pop

베열의 맨 뒤에 있는 요소를 제거하고 반환

let arr2 = [1, 2, 3];
const poppedItem = arr2.pop();

console.log(poppedItem);
// 콘솔 : 3
console.log(arr2);
// 콘솔 : [1, 2]

 

shift

배열의 맨 앞에 있는 요소를 제거하고 반환

let arr3 = [1, 2, 3];
const shiftedItem = arr2.shift();

console.log(shiftedItem);
// 콘솔 : 1
console.log(arr3);
// 콘솔 : [2, 3]

 

 

unshift

배열의 맨 앞에 새로운 요소를 추가하는 메서드

let arr4 ] [1, 2, 3];
arr4.unshift(0);

console.log(arr4);
// 콘솔 : [0, 1, 2, 3];

 

shift 와 unshift는 비교적 push나 pop보다는 느리게 동작함 
그렇기에 되도록 push나 pop을 이용하여 해결하는게 좋음

 

 

slice

배열의 특정 범위를 잘라내서 새로운 배열로 반환

ler arr5 = [1, 2, 3, 4, 5];
let sliced = arr5.slice(2, 5);
console.log(sliced);
// 콘솔 : [3, 4, 5]

console.log(arr5);
// 콘솔 : [1, 2, 3, 4, 5]

let sliced2 = arr5.slice(2);
console.log(sliced2);
// 콘솔 : [3, 4, 5]

// 배열 뒤에서부터 자르고 싶을때는 음수
let sliced3 = arr5.slice(-1);
console.log(sliced3);
// 콘솔 : [5]

 

 

concat

두 개의 서로 다른 배열을 이어 붙여서 새로운 배열을 반환

let arr6 = [1, 2];
let arr7 = [3, 4];

let concatedArr = arr6.concat(arr7);
console.log(concatedArr);
// 콘솔 : [1, 2, 3, 4]

 

 

순회와 탐색

forEach

배열의 모든 요소를 순회하면서, 각각의 요소에 특정 동작을 수행시키는 메서드

let arr1 = [1, 2, 3];

arr1.forEach(function (item, idx, arr) {
console.log(idx, item * 2);
});

// 콘솔 : 0 2 / 1 4 / 2 6
let arr1 = [1, 2, 3];

let doubledArr = [];

arr1.forEach((item) => {
doubledArr.push(item *2);
});

console.log(doubledArr);
// 콘솔 : [2, 4, 6]

 

 

includes

배열에 특정 요소가 있는지 확인하는 메서드

let arr2 = [1, 2, 3];
let isInclude = arr2.includes(10);

console.log(isInclude);
// 콘솔 : false

 

 

indexOf

특정 요소의 인덱스(위치)를 찾아서 반환하는 메서드

얕은 비교로 비교해서 찾음 

단순한 원시타입을 찾을때 사용

let arr3 = [1, 2, 3];
let index = arr.indexOf(2);

console.log(index);
// 콘솔 : 1
// 존재하지 않는 값을 반환할때는 -1로 반환함

 

findIndex

모든 요소를 순회하면서, 콜백함수를 만족하는 특정 요소의 인덱스(위치)를 반환하는 메서드

복잡한 객체를 찾을때 사용

let arr = [1, 2, 3];
const findedIndex = arr4.findIndex((item) => {
if (item === 2) return true;
});

console.log(findedIndex);
// 콘솔 : 1


//간단하게 정리하면
const findedIndex = arr4.findIndex((item) => item === 2);
let objArr = [
{name : "KUN"},
{name : "조쿤"},
];

console.log(objArr.indexOf({name : "KUN"}));
// 콘솔 : -1 (못찾음)

console.log(objArr.findIndex((item)=> item.name === "KUN"));
// 콘솔 : 0

 

 

find

모든 요소를 순회하면서 콜백 함수를 만족하는 요소를 찾는데, 요소를 그대로 반환함

let arr5 = [
{name : "KUN"},
{name : "조쿤"},
];

const finded = arr5.find((item) => item.name === "KUN");
console.log(finded);
//콘솔 : {name : "KUN"}

 

 

배열 변형

filter

기존 배열에서 조건을 만족하는 요소들만 필터링하여 새로운 배열로 반환

웹서비스에서 특정조건에서 검색시키는 기능이나 카테고리별 필터  기능을 개발할때 필수적으로 사용되는 메서드

let arr1 = [
{name : "KUN", hobby : "산책"},
{name : "쿤", hobby : "산책"},
{name : "조쿤", hobby : "터그"},
];

const walkDog = arr1.filter((item) => {
if(item.hobby === "산책") return true;
});

console.log(walkDog);
//콘솔 : 
// [{name : "KUN", hobby : "산책"},
// {name : "쿤", hobby : "산책"}];


// 더 간단하게 개선
const walkDog = arr1.filter(
(item) => tem.hobby === "산책"
);

 

 

map 

배열의 모든 요소를 순회하면서, 각각 콜백함수를 실행하고 그 결과값들을 모아서 새로운 배열로 반환

let arr2 = [1, 2, 3];
const mapResult1 = arr2.map((item, idx, arr) => {
return item * 2;
});

console.log(mapResult1);
// 콘솔 : [2, 4, 6];
let arr1 = [
{name : "KUN", hobby : "산책"},
{name : "쿤", hobby : "산책"},
{name : "조쿤", hobby : "터그"},
];


let names = arr1.map((item) => item.name);
console.log(names);
// 콘솔 : ['KUN', '쿤', '조쿤']

 

 

sort

배열을 사전순으로 정렬하는 메서드

let arr3 = ["b", "a", "c"];
arr3.sort();

console.log(arr3);
// 콘솔  : ['a', 'b', 'c']

 

사전순으로 정렬하기때문에 숫자의 대소관계로는 정렬이 안됨 -> 이럴 경우 콜백 함수를 정의해줘야함

let arr3 = [ 10, 3, 5];

//오름차순 정렬
arr3.sort((a, b) => {
if( a > b){
//b가 a 앞에 와라 
return 1; 
}else if( a < b){
// a가 b 앞에 와라
return -1;
}else {
// 두 값의 자리를 바꾸지 마라 
return 0;
}
});

console.log(arr3);
// 콘솔 : [3, 5, 10]

 

 

toSorted

정렬된 새로운 배열을 반환하는 메서드

let arr5 = ["c", "a", "b"];
const sorted = arr5.toSorted();

console.log(arr5);
//콘솔 : ['c', 'a', 'b']

console.log(sorted);
// 콘솔 : ['a', 'b', 'c']

 

 

join

배열의 모든 요소를 하나의 문자열로 합쳐서 반환하는 메서드

let arr6 = ["hi", "im", "kun"];
const joined = arr6.join();
console.log(joined);
//콘솔 : hi,im,kun

// 구분자 바꾸기 가능
const joined = arr6.join(" ");
console.log(joined);
// 콘솔 : hi im kun

 

 


Date 객체와 날짜

Date 객체 생성

let dat1 = new Date(); // 생성자 -> 현재시간 가져옴

let date2 = enw Date("2020-04-26");
// let date2 = enw Date("2020. 04. 26");
// let date2 = enw Date("2020/4/6");
// let date2 = enw Date(2020, 4, 26, 14, 55, 55);

 

타임 스탬프

특정 시간이 "2020.04.26 00시 00분 00초"로 부터 몇 ms가 지났는지를 의미하는 숫자값

여기서 "2020.04.26 00시 00분 00초 는 UTC이다.

let ts1 = date1.getTime();

let date4 = new Date(ts1);
// 타임스탬프에 해당하는 날짜로 저장됨

 

 

시간 요소 추출

let year = data1.getFullYear();
let month = deat1.getMonth() + 1; // 자바스크립트는 1월이 0으로 나와서 +1을 해줘야함
let date = date1.getDate();

let hour = date1.getHoures();
let minut = date1.getMinutes();
let seconds = date1.getSeconds();

 

 

시간 수정

date1.setFullYear(2024);
date1.setMonth(2); //실제로는 3월
date1.setDate(30);
date1.setHoures(23);
date1.setMinutes(59);
date1.setSeconds(59);

 

 

시간을 여러 포맷으로 출력

console.log(date1.toDateString());
console.log(date1.toLocaleString());

 

 


 

 

동기와 비동기

동기

여러개의 작업을 순서대로 하나씩 처리하는 방식

자바스크립트는 동기적으로 코드를 실행함 

 

단점 : 하나의 task가 끝나기전에는 다음 task가 실행되지 않기때문에 성능 이슈가 있음. 프로그램 성능 악화.

 

JAVA나 C#에서는 멀티쓰레드를 활용하지만, 자바스크립트 엔진에는 쓰레드가 하나 뿐임.

 

 

비동기 

동기적이지 않다는 뜻으로

작업을 순서대로 처리하지 않음 

 

console.log(1);

// 3초뒤에 callback 함수 실행
setTimeout(() => {
console.log(2);
}, 3000);

console.log(3);

// 콘솔 : 1 / 3 / 2

 

 

자바스크립트 엔진에는 쓰레드가 하나 뿐이락 했는데 어떻게 동시에 작업을 처리할수 있는지!?
:: 비동기 작업들은 자바스크립트 엔진이 아닌 Web APIs에서 실행 됨 

 

비동기 처리

콜백함수를 이용하여 사용 

function add(a, b, callback){
setTimeout(()=> {
const sum = a + b;
callback(sum);
}, 3000);
}

add(1, 2, (value) => {
console.log(value);
});

 

비동기작업의 결과를 또다른 비동기 작업의 인수로 활용 가능함

이러한 형태로 작업하면 인덴트(들여쓰기)가 계속 되어서 콜백지옥이 생김 -> 해결방법은 Primise

 

 

Promise

비동기 작업을 효율적으로 처리할 수 있도록 도와주는 자바스크립트의 내장 객체 

(비동기 작업을 감싸는 객체)

 

resolce와 reject에 인수로 결과값을 전달할 수 있음

const promise = new Promise((resolve, reject) => {
//비동기 작업을 실행하는 함수 : executor

setTimeout(() => {
console.log("안녕");
reject("왜 실패했는지 이유...");
}, 2000);
});


setTimeout(()=> {
console.log(promise);
}, 3000);

 

 

 

promise가 관리하는 비동기작업이 성공하거나 실패했을때의 결과값을 이용할 수 있음

const promise = new Promise((resolve, reject) => {
//비동기 작업을 실행하는 함수 : executor

setTimeout(() => {
const num = 10;

if(typeof num === "number"){
resolve(num + 10);
}else {
reject ("num이 숫자가 아닙니다");
}
}, 2000);
});

//promise가 성공하게 되면 then메서드에 전달한 callback 함수를 실행함 
promise.then((value) => {
console.log(value);
});
//콘솔 : 20 

// promise가 실패했을때 콜백함수 실행
promise.catch((error) => {
console.log(error);
});

 

then과 catch는 promise 객체를 반환하기 때문에 아래와 같이 사용할 수 있음

promise.then((value) => {
console.log(value);
}).catch((error) => {
console.log(error);
});

 

 

함수에 넣어서 매개변수 받도록 사용하기

function add10(num) {
const promise = new Promise((resolve, reject) => {

setTimeout(() => {
const num = 10;

if(typeof num === "number"){
resolve(num + 10);
}else {
reject ("num이 숫자가 아닙니다");
}
}, 2000);
});

return promise;
}

const p = add10(0);
p.then((result) => P
console.log(result);

	const newP = add10(result);
	newP.then((result) => {
	console.log(result);
    });
});
// 콘솔 : 10 / 20

여기서 아까 위에서처럼 비동기 작업할때 들여쓰기가 많이 되는 경우가 발생할 수 있음

그럴 때 아래와 같이 개선할 수 있다.

 

add10(0)
.then((result) => {
	console.log(result);
    return add10(result);
    })
    .then((result) => {
    console.log(result);
    return add10(result);
    })
    .then((result) => {
    console.log(result);
    }).catch((error) => {
    console.log(error);
    });
// 콘솔 10 / 20 / 30

 

 

async / await

어떤 함수를 비동기 함수로 만들어주는 키워드

 

async

함수 앞에 붙여서 사용함 

함수가 promise를 반환하도록 변환해주는 키워드

async function getData(){
	return {
	name : "쿤",
	id : "dog",
	}
}

console.log(getData());

 

await

async 함수 내부에서만 사용이 가능한 키워드

비동기 함수가 다 처리되기를 기다리는 역할 

async function getData(){
// async 함수안에서 promise를 사용하면 그대로 promise를 반환힘
	retrun new Promise((resolve, reject) => {
    	setTimeout(() => {
        resolve({
		name : "쿤",
		id : "dog",
		});
        }. 1500);
    });
}

async function printData() {
coinst data = await getData();
}

printData();