강의
학습 목표.
1. 참조형 타입 특징의 이해.
2. 배열의 다양한 메서드를 구분하고 사용할 수 있다.
3. 객체를 복사하고 수정하는 방법을 적용할 수 있다.
4. 콜백 함수가 무엇인지 이해하고 배열 메서드에서 콜백 함수를 사용하는 방법을 익힐 수 있다.
배열은 순서를 지니는 참조형 데이터.
let fruits = ['Apple', 'Banana', 'Cherry'];
console.log(fruits); // ['Apple', 'Banana', 'Cherry']
// 배열 요소 수정
fruits[1] = 'Blueberry';
console.log(fruits); // ['Apple', 'Blueberry', 'Cherry']
배열 요소를 수정하는 법.
let original = [{ fruit: 'Apple' }, { fruit: 'Banana' }, { fruit: 'Cherry' }];
let shallowCopy = [...original]; // 얕은 복사
// let referenceCopy = original; // 이건 얕은 복사가 아닙니다. 첫 번째 특징 위반. 주소값이 완전히 동일해요.
// shallowCopy의 첫 번째 요소를 수정
shallowCopy[1].fruit = 'Blueberry';
console.log(original); // [{ fruit: 'Apple' }, { fruit: 'Blueberry' }, { fruit: 'Cherry' }]
console.log(shallowCopy); // [{ fruit: 'Apple' }, { fruit: 'Blueberry' }, { fruit: 'Cherry' }]
배열을 얕은 복사하는 법.
껍데기는 다르지만, 속은 똑같다.
function deepCopyArray(arr) {
var result = [];
for (var i = 0; i < arr.length; i++) {
if (typeof arr[i] === 'object' && arr[i] !== null) {
// 객체나 배열이면 재귀적으로 복사
result[i] = deepCopyArray(arr[i]);
} else {
// 원시값이면 그대로 복사
result[i] = arr[i];
}
}
return result;
}
let originalArray = ['Apple', ['Banana', 'Cherry'], 'Date'];
let copiedArray = deepCopyArray(originalArray);
// 깊은 복사 후 수정
copiedArray[1][0] = 'Blueberry';
console.log(originalArray); // ['Apple', ['Banana', 'Cherry'], 'Date']
console.log(copiedArray); // ['Apple', ['Blueberry', 'Cherry'], 'Date']
깊은 복사.
만일 얕은 복사를 하면 배열 안에 참조형 배열이 또 있을 경우에는 문제가 생긴다. 카피본을 수정할 때, 원본까지 수정되기 때문이다.
Array.isArray()-> 괄호 안에 든 게 배열인지 아닌지 확인 가능한 메서드이다.
const _ = require('lodash');
let originalArray = [
['Apple', 'Banana'],
{ fruit: 'Cherry', color: 'Red' },
42,
];
// Lodash cloneDeep을 이용한 깊은 복사
let deepCopiedArray = _.cloneDeep(originalArray);
// 복사본에서 값을 변경
deepCopiedArray[0][1] = 'Blueberry';
deepCopiedArray[1].fruit = 'Blueberry';
console.log('원본 배열:', originalArray);
console.log('깊은 복사 배열:', deepCopiedArray);
실전에서는 라이브러리를 쓴다...
객체
const propName = "age";
const person = {
name: "John",
[propName]: 30, // 'age'라는 속성명이 동적으로 생성됨
["greet" + "ing"]: "Hello", // 'greeting'이라는 속성명도 동적으로 생성됨
};
console.log(person);
// 출력: { name: 'John', age: 30, greeting: 'Hello' }
이런 식으로 대괄호 안에 스트링이 들어간 변수를 투입하면 속성명이 생성된다. 나중에 쓸 일이 생길 지도.
// 객체에서 비공개 속성을 관리하고자 할 경우
const secretKey = Symbol('secret');
let obj = {
name: "John",
age: 30,
[secretKey]: "Sensitive Information"
};
for (let key in obj) {
console.log(key); // name, age (Symbol은 표시되지 않음)
}
console.log(obj[secretKey]); // 출력: "Sensitive Information"
얕은 복사 = 성능이 중요하거나, 내부 속성이 원시값으로만 이루어져 있거나.
메서드의 사용에 앞서, 이게 원본을 변경하는지, 안 하는 지를 생각해보고 써야만 한다.
배열 메서드들
변경 (mutable)
1. push
2. pop
3. shift
4. unshift
5. splice
6. sort -> 그냥 빈 채로 쓰면 유니코드 순으로 정렬이 된다.
비변경
1. concat / 레거시에 가깝다. 요즘에는 스프레드 연산자를 써서..
2. slice()
3. join()
4. includes()
5. indexOf()
6. forEach()
7. map() 진짜 중요함.
8. filter()
객체 메서드들
1. Object.keys() 객체의 열거 가능한 속성 이름들을 배열로 반환.
2. Object.values() 객체의 열거 가능한 밸류를 배열로 반환.
3. Object.entries() 객체의 키값쌍을 배열로 반환. - db에 집어넣을 때 많이 씀
4. Object.assign() 하나 이상의 출처 객체로부터 대상 객체에 속성을 복사.
5. Object.freeze() 객체를 동결하여 더는 수정할 수 없게 만든다.
6. Object.seal() 객체를 얼리되 내부 값은 변경 가능.
개인과제 프로그레스
const urlPopularPage =
const main = document.querySelector("main");
const cardWrapper = document.querySelector(".cardWrapper");
const searchBox = document.getElementById("searchBox");
const searchInput = document.querySelector(".searchInput");
const cards = document.querySelectorAll(".tempcard");
const modalContainer = document.getElementById("modalContainer");
const fixBtn = document.getElementById("fixBtn");
const options = {
method: "GET",
headers: {
accept: "application/json",
Authorization:
"Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJlYTNkZjlkMmFlMjRiZGQ5Y2E1Y2YxZWE0YjBlZGZlZSIsIm5iZiI6MTcyODk2NDkzNy4yNDIyMjgsInN1YiI6IjY3MGRlNTdhOWYzNTMxZTZiMjZjNDU5OCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.npK2DJ6_sFT87OLxSowunNArjpxCtQ-dPQrI9ppT1yE",
},
};
fetch(urlPopularPage, options)
.then((res) => res.json())
.then((data) => {
for (i = 0; i < data.results.length; i++) {
const popularCards = `<div class="tempcard">
<img
alt="영화 이미지를 가지고 올 수 없습니다."
style="width: 200px; height: 300px;"
/>
<ul class="contentWrapper">
<li class="movieTitle">${data.results[i].title}</li>
<li class="movieScore">평점 : ${data.results[i].vote_average}</li>
<li class="movieId">${data.results[i].id}</li>
</ul>
</div>`;
cardWrapper.innerHTML += popularCards;
}
})
.catch((err) => console.error("error:" + err));
searchBox.addEventListener("submit", function (e) {
// 검색창 submit와 관련된 코드입니다.
e.preventDefault();
const userInput = searchInput.value;
const encodedQuery = encodeURIComponent(userInput); // 유저가 쓴 데이터를 인코딩해줘요!
// 이렇게 안 바꿔주면 아래 searchPage를 통한 검색이 불가능!
console.log(encodedQuery);
cardWrapper.innerHTML = ""; // cardWrapper 안의 데이터를 초기화시켜줘요!
fetch(searchPage, options)
.then((res) => res.json())
.then((data) => {
for (i = 0; i < data.results.length; i++) {
const popularPages = `<div class="tempcard">
<img
alt="영화 이미지를 가지고 올 수 없습니다."
style="width: 200px; height: 300px;"
/>
<ul class="contentWrapper">
<li class="movieTitle">${data.results[i].title}</li>
<li class="movieScore">평점 : ${data.results[i].vote_average}</li>
<li class="movieId">${data.results[i].id}</li>
</ul>
</div>`;
cardWrapper.innerHTML += popularPages;
}
})
.catch((err) => console.error("error:" + err));
});
cardWrapper.addEventListener("click", function (e) {
// cardWrapper의 자식 요소 중에서 가장 가까운 tempcard를 선택.
if (e.target.closest(".tempcard")) {
modalContainer.style.display = "flex";
modalContainer.innerHTML = "";
// 이렇게 안의 html을 초기화하지 않으면 closeBtn이 작동하지 않아요!!
const targetedCard = e.target.closest(".tempcard");
const targetedCardId = targetedCard.querySelector(".movieId").innerText;
// movieId를 카드 안에 숨겨두었는데, 그 값을 받아오는 코드에요!
fetch(modalCardUrl, options)
.then((res) => res.json())
.then((data) => {
const modalCardHtml = `<div class="modalCard">
<button class="closeBtn">닫기</button>
<img
alt="영화의 이미지가 표현됩니다."
style="width: 480px; height: 640px;"
/>
<ul class="contentWrapper">
<li class="movieIntroduce">${data.overview}</li>
<li class="movieTitle">${data.title}</li>
<li class="movieScore">평점 : ${data.vote_average}</li>
</ul>
</div>`;
modalContainer.innerHTML += modalCardHtml;
const closeBtn = document.querySelector(".closeBtn");
closeBtn.addEventListener("click", function () {
modalContainer.style.display = "none";
});
})
.catch((err) => console.error("error:" + err));
}
});
fixBtn.addEventListener("click", function (){
window.location.reload()
});