Javascript 고차 함수 및 구조 분해 할당 학습
DOM 및 React 활용을 위한 JSX 기초 학습
Spread 연산자(Operator)
배열 또는 객체를 풀어서 인자로 전달하거나, 각각의 요소로 넣을 때 사용 - ES6에서 도입됨
const arr1 = [0, 1, 2];
const arr2 = [3, 4, 5];
const concatenated = [...arr1, ...arr2]; // 여러 개의 배열을 이어 붙일 수 있습니다.
console.log(concatenated); // [0, 1, 2, 3, 4, 5]
const arr3 = [1, 2, 3];
const spread = [0, ...arr3, 4]; // 이어붙여 만들어진 배열은 원본에 영향을 주지 않습니다.
console.log(spread); // [0, 1, 2, 3, 4]
Spread 문법은 배열 또는 객체를 합치거나, 복사할 때 강력한 힘을 발휘합니다.
또한, Spread 문법은 기존 배열을 변경하지 않고(immutable), 새로운 배열을 반환하여 참조 자료형인 배열, 객체의 기존 배열을 변경하려면 새로 할당해야 합니다.
const jPopPlayList = {
sekaiNoOwari: 'RPG',
aimyon: 'Harunohi',
backNumber: 'Mabataki',
};
const kPopPlayList = {
wonstein: 'Laser',
gDragon: 'R.O.D',
bigbang: ['Blue', 'Loser'], // bigbang key는 복사된 객체에서 수정이 발생하면, 원본 value도 수정이 발생하게 됩니다.
};
const mergedPlaylist = { ...jPopPlayList, ...kPopPlaylist };
객체를 복사할 때도 Spread 연산자를 활용할 수 있습니다.
Spread 연산자를 활용하면 원본 데이터의 수정을 방지할 수 있습니다. 이를 '깊은 복사(Deep copy)'라 합니다.
그러나, 이는 깊이가 1일 때에만 유효합니다.
다차원 배열, 객체의 경우 깊이가 1보다 큰 데이터의 수정이 발생할 경우, 원본 데이터도 수정되는 이른바 '얕은 복사(Shallow copy)'가 발생합니다.
Rest
Rest 문법은 입력인자를 배열의 형태로 받아 사용할 수 있습니다. 입력인자의 갯수가 가변적일 때 유용하게 사용할 수 있습니다.
function sum(...nums) {
let sum = 0;
for (let i = 0; i < nums.length; i++) {
sum = sum + nums[i];
}
return sum;
}
console.log(sum(1,2,3)) // return 6
console.log(sum(1,2,3,4)) // return 10
입력인자를 배열의 형태로 다룰 수 있고, 입력인자의 수가 정해져 있지 않을 때도, 위처럼 사용할 수 있습니다.
Spread 와 Rest의 다른 점은 Spread 연산자는 배열을 개별적으로 전개합니다. Rest는 개별적인 입력을 배열로 묶어줄 수 있습니다.
구조 분해 할당은 Spread 문법을 이용해 값을 해체, 개별 값을 변수에 새로 할당하는 과정입니다.
const [a, b, ...rest] = ['s', 'h', 'i', 't', 'a', 'i', 'k', 'o', 't', 'o'];
console.log(a) // 's'
console.log(b) // 'h'
console.log(rest) // ["i", "t", "a", "i", "k", "o", "t", "o"]
Rest 문법을 사용한 구조 분해 할당의 경우, Rest 문법 이후에 다른 입력인자를 추가할 수 없습니다.
const kbo = ['samsung', 'kia', 'nc', 'kiwoon', 'lg', 'ssg', 'hanhwa', 'lotte', 'kt', 'dusan'];
const [myFavorite, ...rest] = kbo
console.log(myFavorite) // 'samsung'
객체 분해에도 적용할 수 있습니다.
const profile = {
name: 'shitaikoto',
myFavorite: {
band: 'back number',
actor: 'suda masaki',
job: 'developer'
}
}
const changedJob = {
...profile,
myFavorite: {
...profile.myFavorite,
job: 'designer'
}
}
const {name} = profile
console.log(name) // "shitaikoto"
console.log(changedJob) // profile.myFavorite.job 의 value 변경
함수를 이용해 객체를 분해할 수 있습니다.
const profile = {
name: 'shitaikoto',
myFavorite: {
band: 'back number',
actor: 'suda masaki',
job: 'developer'
}
}
function iwant({name: name, myFavorite: {job: job}}) {
console.log(name + " want to be a " + job);
}
iwant(profile) // 'shitaikoto want to be a developer'
일급 객체(first-class citizen)의 세 가지 특징을 설명할 수 있다.
고차 함수(higher-order function)에 대해 설명할 수 있다.
고차 함수를 자바스크립트로 작성할 수 있다.
Javascript에서 함수는 일급 객체(First-class citizen)입니다.
일급 객체(First-class citizen, object)란, 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 가리킵니다.
Javascript에서 일급 객체는 몇가지 특징이 있습니다.
일급 객체는 위와 같은 특징이 있으며, 이러한 특권을 누릴 수 있는 대표적인 일급 객체는 함수입니다.
함수에 일급 객체의 세가지 특징을 적용해보면 다음과 같습니다.
일급 객체인 함수는 변수에 할당할 수 있고, 또한 배열의 요소, 객체의 value로 저장할 수 있습니다.
let nowYear = new Date().getFullYear(); // return 현재 년도(2021)
const getKoreanAge = function(birthYear) {
return nowYear - birthYear + 1;
}; // 현재 년도를 기준으로 한국식 나이가 몇살인지?
console.log(getKoreanAge(2000)) // return 22
위는 변수 getKoreanAge
에 한국식 나이를 구하는 함수를 할당한 함수 표현식 입니다.
변수엔 함수가 저장돼있기 때문에, 호출 연산자를 활용할 수 있습니다.
위의 예시로 든 함수를 다른 함수의 인자로 전달할 수 있습니다.
또한, 인자로 전달된 함수의 결과를 리턴할 수 있습니다.
function getAge (func, num){
return func(num);
}
let result = getAge(getKoreanAge,2000);
console.log(result) // 22
여기서, getKoreanAge
를 입력인자로 받는 함수 getAge는
고차함수(Higher order Function)가 되며, getKoreanAge
는 콜백(callback)함수가 됩니다.
콜백 함수(callback function)란, 다른 함수의 입력인자로 전달되는 함수를 의미합니다.
고차함수(Higher order Function)의 모양새는 특이합니다. 함수를 리턴하기 때문입니다. '함수를 리턴하는 함수' 또는, '함수를 인자로 받는 함수'는 고차함수가 될 수 있습니다.
Javascript에는 기본적으로 내장된 고차함수가 여러가지 있습니다. 배열과 관련된 메소드 중 일부가 대표적인 고차함수에 해당되며, filter
, map
, reduce
등이 있습니다.
이와 관련하여 내장 고차함수를 더 공부해 업로드 하겠습니다!
DOM(Document Object Model) : 문서 객체 모델(The Document Object Model, 이하 DOM) 은 HTML, XML 문서의 프로그래밍 interface 이다. - 출처
DOM은 HTML을 프로그래머의 관점으로 바라본 것입니다. 웹 페이지는 일종의 문서이고, 이 문서는 웹 브라우저를 통해 문서가 해석되어 웹 브라우저 화면에 나타나거나, HTML 소스 자체로 나타나기도 합니다.
동일한 문서를 사용하여 다양한 형태로 표현할 수 있다는 점에서, DOM은 동일한 문서를 표현, 저장, 그리고 조작하는 방법을 제공합니다. DOM은 웹 페이지의 객체 지향 표현이며, Javascript를 통해 DOM을 수정할 수 있습니다.
DOM은 프로그래밍 언어는 아닙니다. 하지만, DOM이 없다면 Javascript는 웹 페이지의 여러 요소들(html 문서, header, table, text)과 관련된 정보를 갖지 못하게 됩니다. 위 요소들은 웹 문서를 위한 Document Object Model의 한 부분이며, 즉 이러한 요소들을 DOM과 Javascript와 같은 언어를 통해 접근하고 조작할 수 있는 것입니다.
2017년 독일로 놀러갔을 때 찍었던 베를린 돔(Berliner Dom)!
거대한 구조물인 돔이 있고, 그 돔을 겨울엔 따뜻하게, 여름엔 시원하게, 낡은 창문은 수리하고, 청소를 해가며 단순한 건물이 마치 살아 움직이는 것(?) 처럼 유지합니다.
이 베를린 돔을 구성하는 요소들(대문, 동상, 창문, 큰방, 작은방(?).. 등이 DOM 구조가 되고, 망치, 빗자루, CCTV, 에어컨 등 살아있는 건물을 만드는 도구들이 Javascript가 될 수 있겠습니다!
HTML에 Javascript를 적용하기 위해선 <script>
태그를 이용합니다.
<script>
태그를 추가하는 두가지 방법이 있습니다.
<head>
안쪽에 삽입하는 경우<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
<!-- script 요소 삽입 위치 -->
<script src="script.js"></script>
</head>
<body>
<div>Hello JavaScript!</div>
</body>
</html>
<body>
태그가 끝나기 전에 삽입하는 경우<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div>Hello JavaScript!</div>
<!-- script 요소 삽입 위치 -->
<script src="script.js"></script>
</body>
</html>
브라우저는 HTML의 구조와 CSS를 렌더링하는 중 Javascript를 만나면 이에 대한 해석과 구현이 완료될 때 까지 렌더링을 멈춥니다.
헤드에 삽입될 경우, 특히 무거운 스크립트가 실행될 경우, 렌더링에 방해가 되어 오랫동안 완성되지 못한 화면을 노출하게 됩니다. 즉, 로딩 시간이 길어집니다.
집이 아직 지어지지도 않았는데, 침대, 책상, 컴퓨터, 에어컨, 청소 도구 등을 먼저 가져간 느낌입니다. 지어지는데 더 시간이 늦춰질 것 같습니다...
그래서 헤드에 삽입되는 스크립트는 HTML을 재설정하는 가벼운 스크립트들이 자주 사용됩니다.
바디에 삽입될 경우, 브라우저의 렌더링이 완료된 상태에서 스크립트가 실행됩니다. 웹 페이지의 콘텐츠를 변경하는 스크립트의 경우, 화면에 노출된 채로 변화되게 됩니다.
대부분의 스크립트 태그의 위치로 추천되는 위치이며, 문서의 DOM 구성이 완려된 시점에 실행되므로 별다른 추가 설정이 필요하지 않습니다.
Document 객체에는 여러가지 속성과 다양한 메소드가 존재합니다. 이 기술들을 내 손발처럼 자유자재로 사용하기 위해, CRUD(Create, Read, Update and Delete)를 먼저 이해해야 합니다.
document 객체의 createElement 메소드를 이용하면 HTML 요소를 생성할 수 있습니다.
const myDiv = document.createElement('div')
myDiv.textContent = 'Hello Velog!' // <div></div> 빈 div에 텍스트를 추가하는 textContent 메소드
div
태그를 만들고, 그 안에 내용을 추가했는데, 아무것도 보이지 않습니다.
myDiv
라는 div
요소는 현재 HTML 문서를 브라우저에 렌더링되는 영역에 포함되어있지 않기 때문입니다.
이 붕 떠있는 myDiv
요소를 웹 브라우저에 표현하기 위해선 Append를 사용해야 합니다. Append는 지정한 요소의 자식 요소로 붙이는 메소드입니다.
const myDiv = document.createElement('div')
myDiv.textContent = 'Hello Velog!'
document.body.appendChild(myDiv);
부모 요소인 <body></body>
안에 방금 만든 myDiv
를 자식 요소로 붙이기 위해 appendChild 메소드를 사용하면 웹 브라우저에 표현할 수 있습니다.
DOM으로 HTML 엘리먼트의 정보를 조회하기 위해 querySelector를 이용할 수 있습니다.
입력인자에 클래스 이름(.class), ID("#id"), 또는 태그("div") 등을 전달하는 것으로 HTML 요소의 정보를 읽을 수 있습니다.
const getEl = document.querySelectorAll('.className');
// class 이름이 classname인 모든 HTML 요소를 유사 배열로 받아옵니다.
querySelector
와 querySelectorAll
의 차이는, 전자는 입력인자에 일치하는 최상단 요소 하나만 받아옵니다. 후자는 입력인자와 같은 요소들을 전부 받아옵니다.
독립적인 의미를 가진 ID의 경우, querySelector('#id')
를 사용하고, 여러개가 존재할 수 있는 class는 querySelectorAll('.class')
를 사용하면 될 것 같습니다.
기존에 생성하고, 부모 요소에 추가한 DOM 객체를 업데이트하여 다양한 작업을 수행할 수 있습니다.
위에 잠깐 말씀드렸던, textContent
를 이용해 DOM 객체의 value
를 추가 및 수정할 수 있습니다.
또한, 생성한 DOM 객체는 현재 id, class가 지정되어있지 않습니다. 이 경우, CSS 스타일링이 적용되지 않습니다. CSS 스타일링을 적용하기 위해 div 엘리먼트에 class를 추가할 수 있습니다.
const myDiv = document.createElement('div')
myDiv.textContent = 'Hello Velog!'
myDiv.classList.add('myDiv')
document.body.appendChild(myDiv);
console.log(myDiv); // <div class="myDiv">Hello Velog!</div>
요소를 삭제하는 방법은 여러가지가 있습니다. 삭제하고자 하는 요소의 위치를 알 경우, remove
를 사용해 요소를 삭제할 수 있습니다.
myDiv.remove()
여러 개의 요소를 지우기 위해, 반복문을 사용할 수 있습니다.
어떤 부모 요소의 모든 자식 요소를 지우고자 한다면 다음과 같이 표현할 수 있습니다.
const myUl = document.createElement('ul')
const myLi = document.createElement('li')
document.body.append(myUl);
myUl.append(myLi);
// document.body의 첫번째 자식요소가 존재할 때, 반복문이 실행됩니다.
// 반복이 실행될 때, document.body의 첫번째 자식요소를 삭제합니다.
while(document.body.firstChild){
document.body.removeChild(document.body.firstChild)
};
반복문의 조건을 달리하여 원하는 요소만 삭제할 수 있습니다.
모든 웹 사이트는 각각의 기능을 하는 요소들이 있고, 그 요소들을 시각적으로 표현하는 이미지나 버튼이 있습니다.
이러한 이미지나 버튼을 클릭하거나, 드래그 하는 등, 사용자의 입력에 따라 발생하는 이벤트들이 있습니다.
사용자가 요소에 어떤 이벤트를 발생시켰을 때, 이벤트의 결과를 반환하는 이벤트 핸들러를 요소에 적용해야 합니다.
어떤 버튼을 클릭했을 때, 발생하는 이벤트 핸들러를 작성할 경우,
onClick
또는 addEventListener
를 사용합니다.
const btn = document.querySelectorAll('button');
btn.onclick(function)
or
btn.addEventListner('click',function)
( )
안에는 이벤트 핸들러 함수가 들어가게 됩니다. 여기서 주의할 점은, 함수 자체(function)를 할당해야한다는 것입니다. 함수의 결과값(function())을 할당하게 되면, 버튼을 클릭했을 때 단 한 번만 이벤트가 실행됩니다.
우리가 원하는 건, 클릭했을 때마다 해당 함수가 실행되어야 하기 때문에, 함수 자체를 할당해야 합니다.
위처럼 반복문을 이용해 동일한 className
을 가진 button
요소를 가져왔고, 여러 개의 class
가 존재할 경우, 유사 배열로 가져오기 때문에, 반복문을 활용해 .btn
클래스에 각각 이벤트 핸들러를 적용했습니다.
버튼을 클릭하면, 버튼의 textContent
을 알림 창에 띄우는 이벤트 함수를 작성하여 이벤트 핸들러에 할당했습니다.
클릭했을 때의 이벤트 외에도, 이벤트 객체는 굉장히 다양합니다.
이상으로 4주차 학습 내용을 간략히 정리해보았습니다.
아직 웹 개발을 배우는 초반 단계라, 틀린 내용이 있을 수 있습니다.
얼마든지 피드백 주시기 바랍니다!! 긴 글 읽어주셔서 감사합니다. 🙇