2022-11-16: 33가지의 JavaScript 개념 학습 (1)
대망의 JavaScript 개념 학습 시작
예전부터 JavaScript의 동작 원리와 문법 개념, 그리고 알아야하는 지식들을 어느 정도 짚고 갈 수 있으면 좋겠다고 생각했는데 이제 그 시간들을 돌아볼 때가 된 것 같다.
부트캠프 때는 이것저것 구현하면서 개념 학습도 동반하도록 유도하다보니 이것도 저것도 공부하지 못하는 상황이 생겼다.
그 점이 너무 답답했었고, 결국 복붙하는 식의 학습이 되어버렸는데 이제는 그렇지 않으니 하나하나 차근차근 공부해가려고 한다.
학습의 기반은 ‘33가지의 자바스크립트 개념’을 기준으로 진행하려고 하며, 순서는 랜덤으로 진행하려 한다.
금일은 처음 공부하는 시간이므로, 가볍게 짚어갈 내용들 위주로 공부해보고자 한다.
목차
1️⃣ 원시 타입과 참조 타입
2️⃣ ==, ===, typeof
3️⃣ 배열의 메소드 - map, reduce, filter
4️⃣ setTimeout, setInterval, requestAnimationFrame
5️⃣ 식(expression) vs 문(statement)
1️⃣ 원시 타입과 참조 타입
원시 타입(Primitive Type)
- 고정된 저장 공간을 차지하는 데이터를 가리킨다.
- 여기서 말하는 ‘고정된 저장 공간’이란, 데이터가 유동적으로 늘어나거나 줄어드는 등의 변화가 생기지 않는 것을 말한다.
- JavaScript의 원시 타입은 대체적으로 값 타입(Value Type)들이 이에 해당한다.
string,number,boolean,null,undefined,symbol,bigint
let i = 5; const j = "Rozelia";- 위와 같이
5라는 값과,“Rozelia”라는 값에는 다른 값을 끼워넣거나 뺄 수 있는 공간이 없다.- 이런 데이터들은 객체가 아니며, 아울러 객체가 아니다보니 메소드를 가질 수 없다.
- 자신의 값 자체가 지정되어 있으므로 자체적인 수정도 불가하다.
- 이런 의미에서 원시 타입의 타입은 ‘불변성’을 가진다.
참조 타입(Reference Type)
- 원시 타입과는 반대로 고정되지 않은 저장 공간을 차지하는 데이터를 가리킨다.
JavaScript의 참조 타입은 원시 타입의 반대를 가리키므로, 객체(
object)를 가리킨다.let rozelia = {보컬: "유키나", 기타: "사요", 베이스: "리사", 드럼: "아코"}- 위와 같이 변수
rozelia의{}안에는보컬: "유키나",기타: "사요",베이스: "리사",드럼: "아코"라는 값들이 담아져 있다. - 이 데이터들을 묶은
{}, 즉 객체에는 새로운 데이터를 추가할 수도 있고 기존의 값을 배제할 수도 있는 등 자체적으로 변화될 수가 있다.- 이러다보니 값들이 유동적으로 바뀔 수 있어 ‘고정되지 않은 저장 공간’을 가진다.
- JavaScript의 객체를 좀 더 세분화하면 배열(
array), 함수(function), 클래스(class)도 참조 타입에 해당한다.
- 위와 같이 변수
원시 타입과 참조 타입의 메모리 할당
- 원시 타입은 하나의 고정적인, 불변적인 값을 가지고 있으므로 메모리에 직접 해당 값을 저장한다.
- 그러나 참조 타입을 저장하기에는 그 값이 변화무쌍하므로 메모리에 저장되는 용량이 계속해서 변할 수 있다.
- 이는 계속해서 메모리에 변화된 값들을 저장해줘야 하므로 부하를 초래할 수 있다.
- 따라서, 참조 타입은 값을 메모리에 직접 저장하지 않으며 그 값을 참조할 수 있는 ‘주소’가 저장된다.
- 별도로 조사할 단어:
symbol,bigint
2️⃣ ==, ===, typeof
내용을 짚고 가기 전에 - JavaScript는 ‘느슨한 타입’의 ‘동적 언어’이다.
엄격한 타입과 느슨한 타입
- C++, C와 같은 언어는 변수를 선언할 때, 이 변수가 어떤 타입인지를 반드시 선언해야 한다.
// C++, C int l = 4; char liznoir = "리즈누아르";이와 같이 타입을 확실하게 정해야하는 경우를 ‘엄격한 타입’이라고 말한다.
- 하지만, JavaScript에서 변수를 선언할 경우 변수를 가리키는 연산자들을 통해 선언한다.
let t = 3; const trinityaile = "트리니티엘";이와 같이 변수를 선언할 때 타입을 확실하게 지정하지 않고 만드는 경우를 ‘느슨한 타입’이라고 말한다.
정적 언어와 동적 언어
- 정적 언어와 동적 언어의 분기점은 프로그램 실행 전후에 타입을 확인하는 데에 있다.
- 정적 언어는 프로그램 실행 전에 변수의 타입을 확인한다.
- 만약, 선언한 변수의 타입과 들어간 값의 타입이 일치하지 않으면 에러를 내뱉는다.
- 타입이 다를 때의 문제를 확인할 수 있어 코드의 안정성이 올라간다.
- 동적 언어는 프로그램 실행 후에 변수의 타입을 확인한다.
- 따라서, 들어간 값의 타입을 체크하여 해당 변수의 타입을 지정해준다.
- 타입을 지정하지 않고 바로 적용한다는 점에서 빠르게 내용을 구현할 수 있다.
JavaScript는 형변환이 자유롭다.
- 이해가 안 될 테니 아래의 코드를 보자.
console.log(2 + 4 + "6"); console.log("2" + 4 + 6);앞의 log는
66이라는 값이 반환되고, 뒤의 log는246이라는 값이 반환된다.앞의 log에서
2+4까지는int, 즉 숫자로 값이 적용되어 더해지지만 뒤에string인“6”이 등장하면서 형변환이 일어나 값이 합쳐짐으로서“66”이라는 문자열로 값이 반환된다.한편, 뒤의 log는 처음에 선언한 문자열인
“2”에 숫자인4와6이 더해지나 문자열에 합쳐지는 형태가 되면서“246”이라는 값이 반환된다.이처럼, 값이 어떤게 들어와 합쳐지냐에 따라서 타입이 자유롭게 변한다. 이것을 ‘느슨한 형변환’이라고 말한다.
==와 ===
- 우선 아래의 이미지를 보자.

- 보통의 코딩 언어들은
==를 통해서 값을 비교한다. 그러나 JavaScript는==도 있지만,===를 통해서도 값을 비교할 수 있다.- 두 개가 분리되는 이유는 비교를 ‘느슨하게’ 하냐와 ‘엄격하게’ 하냐의 차이이다.
4와“4”는 겉으로는 똑같은 값을 가리키지만, 타입을 따지면 엄연히 다른 값을 나타낸다.- 이 때,
==를 이용해 비교하면4와“4”는 느슨한 비교가 적용되는데 JavaScript에서는 두 데이터가 동일한지 묵시적인 형변환을 통해서 값을 비교해준다.- 따라서,
==를 통해 비교하면4와“4”는 같은 값으로 판단되어true를 반환한다.
- 따라서,
- 그러나
===를 이용해 비교하면4와“4”사이에 엄격한 비교가 적용된다.- 두 데이터의 타입까지 비교하게 되므로 두 개가 서로 다른 값으로 판단되어
false를 반환한다.
- 두 데이터의 타입까지 비교하게 되므로 두 개가 서로 다른 값으로 판단되어
- 이 때,
- 따라서 JavaScript에서 타입까지 고려해 확실하게 값을 비교하고 싶다면
===연산자를 이용하는 게 바람직하다.
typeof연산자typeof는 값의 타입을 반환해주는 연산자다.
console.log(typeof "서니피스"); // string console.log(typeof 5); // number console.log(typeof null); // object console.log(typeof undefined); // undefined console.log(typeof true); //boolean console.log(typeof ["사쿠라", "치사", "하루코", "시즈쿠", "레이"]); // object console.log(typeof {그룹명:"서니피스", 인원수: 5}); // object console.log(typeof function sunnyPeace(){console.log("서니피스")}); // function위의 log 코드 옆에 적힌 주석은 해당 내용을 출력할 시에 반환되는 타입을 가리킨다. 해당 연산자를 이용하면 값의 타입을 검사해주므로 유용하게 이용할 수 있다.
단, JavaScript에서 배열(
array)은 객체(object)로 인식하기 때문에 해당 내용이 배열인지 객체인지를 정확하게 체크하고 싶다면 배열 객체의 메소드인Array.isArray(obj)를 활용하여 검사하는 것이 좋다.console.log(Array.isArray(["사쿠라", "치사", "하루코", "시즈쿠", "레이"])); // true console.log(Array.isArray({그룹명:"서니피스", 인원수: 5})); // false
3️⃣ 배열의 메소드 - map, reduce, filter
map()map()메서드는 배열 내의 모든 요소 각각에 대하여 콜백 함수를 통해 나온 결과를 모아 새로운 배열을 만들어준다.
**[배열]**.**map**({**콜백 함수**(**현재값**, 순서, 배열), thisArg)- 콜백 함수: 필수 요소. map 메소드가 작동하면 실행될 내용들.
- 콜백 함수는 아래의 인자를 가진다.
- 현재값: 필수 요소. 각 배열의 현재값을 여기에 저장한다. 일반적인 param이라고 보면 될 것 같다.
- 현재 순서: 옵션 요소. 각 배열의 현재값이 위치한 순서, 즉 인덱스를 받아온다.
- 배열: 옵션 요소. map 메소드가 받아오는 배열을 받아온다.
- thisArg: ****옵션 요소. 콜백 함수 내에서 this를 사용할 때, 그 this에 넣어줄 값을 여기다 저장한다.
map()과forEach()의 차이는map()은 ‘새로운 배열로 만들어준다’는 점이며,forEach()는 ‘기존의 배열에 변화된 내용을 적용’한다는 점이다.
reduce()- 이전 상태와 동작을 받아 새 상태를 리턴하는 함수이다.
**[배열].reduce({콜백함수(**accumulator**,** currentValue, currentIndex, array**}, 시작값)**- 시작값이라고 적은 것은, 콜백함수를 부를 때 저 위치에 값이 있다면 콜백함수의 첫번째 인자(parameter)에 저 값을 넣어준다. 만약 없다면 배열의 첫번째 숫자가 들어간다.
- 또, reduce의 {콜백함수}는 다음과 같이 4개의 인자(parameter)를 가진다.
accumulator첫 번째 인자. 누산기라고 말하는데, 네이버 사전의 뜻을 보면 다음과 같다.
연산의 결과나 중간값을 일시적으로 보관해 두기 위한 기억 장치
- 이 말 그대로 reduce 함수를 통해 배열에서 일어나는 일들을 계속해서 누적해주는 역할을 해주신다.
currentValue- 두 번째 인자. 현재 받아올 요소를 의미한다.
- 시작값이 있다면 currentValue의 시작은 배열의 첫 번째 값이 된다.
- 시작값이 없다면 currentValue의 시작은 배열의 두 번째 값이 된다.
- 두 번째 인자. 현재 받아올 요소를 의미한다.
currentIndex- 세 번째 인자. 현재 받아올 요소의 순서, index를 의미한다.
- 시작값이 있다면 currentIndex의 시작은 0이 된다.
- 시작값이 없다면 currentValue의 시작은 1이 된다.
- 세 번째 인자. 현재 받아올 요소의 순서, index를 의미한다.
array- 네 번째 인자:
reduce()를 호출한 배열이다.
- 네 번째 인자:
filter()filter()메서드는 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환해준다.
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present']; const result = words.filter(word => word.length > 6); console.log(result); // expected output: Array ["exuberant", "destruction", "present"]filter 구문은 다음과 같이 생겼다
[**배열**].**filter**({**콜백함수**(현재값**【요소】**, 순서, 배열)}, thisArg)- 콜백 함수: 필수 요소. 필터를 적용하기 위해 이용할 함수. 콜백 함수의 결과가
true인 값들은 유지하고,false인 값들은 제거한다. - 콜백 함수는 아래의 인자들을 가진다.
- 현재값(요소): 필수 요소. 현재 필터를 이용해 테스트를 거치게 될 대상, 요소.
- 순서: 옵션 요소. 현재 필터를 이용해 테스트를 거치게 될 대상의 순서.
- 배열: 옵션 요소. 현재 필터를 이용하는 배열 그 자체.
- thisArg: 옵션 요소, 콜백 함수를 실행할 때 함수 내부에서 this를 사용 시 받아올 값.
4️⃣ setTimeout, setInterval, requestAnimationFrame
setTimeout()- 일정 시간이 지난 후, 인자로 받은 함수를 실행시켜주는 메소드이다.
setTimeout(**함수**, **지연 시간**, 인자1, ..., 인자n);- 함수: 필수 요소, 지정한 지연 시간이 지나면 설정한 함수의 내용이 실행된다.
- 지연 시간: 필수 요소, 함수가 실행되기까지 작동을 지연시킬 시간을 지정한다.
- 인자1, ..., 인자n: 옵션 요소, 지연 시간이 지나 실행되는 함수에 전달할 매개변수(parameter)를 가리킨다.
- 해당 메소드는 함수를 1회 실행시켜준다.
- 지정된 시간마다 연속적으로 실행시키고 싶다면
setInterval()메소드를 사용해야 한다.
- 지정된 시간마다 연속적으로 실행시키고 싶다면
setTimeout(function () { console.log("밥밥디라라"); }, 5000);setInterval()- 주기적으로 시간이 지날 때마다, 인자로 받은 함수를 실행시켜주는 메소드이다.
setInterval(**함수**, 지연 시간, 인자1, ..., 인자n);- 함수: 필수 요소, 지정한 지연 시간이 지날 때마다 설정한 함수의 내용이 실행된다.
- 지연 시간: 필수 요소, 함수가 주기적으로 실행되기 위한 시간을 지정한다.
- 인자1, ..., 인자n: 옵션 요소, 지연 시간이 지나 실행되는 함수에 전달할 매개변수(parameter)를 가리킨다.
- 주기적으로 작동되는 해당 메소드를 멈추고 싶다면
clearInterval()메소드를 사용한다.
const dingDongDang = setInterval(function() { console.log("딩동댕"); cnt++; if (cnt == 4) { clearInterval(dingDongDang); } }, 6000);requestAnimationFrame()- 해당 메소드는 이름에 적혀있듯 주기적으로 ‘애니메이션’을 적용할 때에 적합한 메소드이다.
- 주기적으로 애니메이션을 작동시키려고 할 때,
setInterval()을 통해서 반복적으로 애니메이션을 구현해낼 수 있지만, 이 경우 브라우저 환경에 따라서 애니메이션을 시작하는 타이밍이나 작동하는 흐름이 원하는 모습대로 나오지 않을 수 있다. (뚝뚝 끊긴다거나, 생각했던 것보다 늦은 타이밍에 적용된다거나.) - 또한,
setInterval()은 애니메이션이 작동하는 화면이 비활성화인 상태에서도 작동이 되므로 계속된 동작으로 인해 메모리를 계속 사용하거나 모바일에서는 배터리 소모의 원인이 되기도 한다. - 따라서, 이러한 문제의 대체제로서
requestAnimationFrame()가 등장하게 됐다.
const character = document.querySelector('.char'); const val = document.querySelector('.value'); let posY = 0; function render() { val.innerHTML = posY; // 현재 Y값이 화면에 출력되도록 한다. charater.style.transform = `translateY(${-posY}px)` // posY가 늘어남에 따라 이미지가 화면 위로 올라간다. posY++; requestAnimationFrame(render); // 메소드를 이용해 render()가 반복적으로 작동하게 만든다. // 즉, 재귀를 시켜 계속해서 posY의 값이 늘어나도록 유도한다. if (posY >= 100) { return cancelAnimationFrame(); // posY의 값이 100이상 되면 반복되는 애니메이션이 작동되지 않도록 한다. } } render(); // render()를 실행시킨다.위의 내용대로
requestAnimationFrame()을 계속해서 반복시켜, 즉 재귀시킴으로서 애니메이션이 동작하도록 유도한다.해당 애니메이션을 멈추게 하고 싶다면
cancelAnimationFrame()을 사용해 멈출 수 있다.- 별도로 조사할 단어: 리플로우, 리페인트, 리렌더링
5️⃣ 식(expression) vs 문(statement)
값(value)
- 값이란 더 이상 생성해내지 못하는, 고정적인 하나의 데이터 혹은 식이다.
1; "나가세 마나"; 1+4;1과"나가세 마나"는 더 이상 값을 생성할 수 없는 고정된 데이터이므로 ‘값’이라고 말할 수 있다.- 그러나,
1+4라는 식은5라는 값으로 값이 생성될 수 있으므로 ‘값’이 아닌 ‘식’이라고 말한다.
식(expression)
- 식, 또는 표현식이라고 말하며 값을 결정짓는 구문, 혹은 값을 만들어내는 코드의 단위이다.
- 하나의 값을 반환할 수 있는 것들은 모두 식이라고 생각하면 된다.
- 식은 값과 변수, 함수, 연산자들의 조합으로 이루어지며, 여러 개를 결합할 수 있다. 아울러 식을 통해 값을 생성해낼 수도 있다.
1; // 숫자 표현식(값) "나가세 마나"; // 문자열 표현식(값) 1 > -1; // 논리 연산식 12 + "10" + 2; // 문자 연산식 everyDay(); // 함수 호출식 - 함수를 호출하면 값이 반환되므로 식으로 여긴다.문(statement)
- 데이터에 어떤 것을 수행하거나 실행시킬 것인지를 결정하는 지시문, 혹은 코드의 단위를 문이라고 말한다.
if (a > 6) { return "심봤다!"; } // 조건문- JavaScript는 식을 문으로도 인정하므로 아래와 같이 작성할 수도 있다.
const c = "문문문"; // 선언문 b = a + 1; // 할당문하지만, 반대로 문이 식으로 인정되진 않는데 문은 어디까지나 역할을 수행하기 위한 지시자의 역할을 하지만 그 자체가 값으로서 반환되지 않기 때문이다.
const bb = if (a > 6) { return "심봤다!"; } // Uncaught SyntaxError: Unexpected token 'if'위의 내용만 봐도 변수
bb에 조건문을 할당했지만, 조건문이 값을 반환하고 있지 않으므로 변수bb에 할당할 수 없다. 이 부분이 문과 식의 큰 차이점이다.함수 표현식(Function Expression)과 함수 선언(Function Declaration)
함수 표현식은 함수를 생성하고 이를 변수의 값으로 가지는 것을 가리킨다.
const functionExpression = () => { console.log("야호!"); }; console.log(functionExpression);변수에 함수를 할당했고, 값을 만들어내지 못한다고 생각하여 ‘문’이라고 생각할 수 있다. 하지만, 위의 코드를 콘솔창에서 확인하면 아래와 같이 나온다.

콘솔에 변수명을 그대로 출력시킨다면 함수의 내용이 나온다. 즉, 값을 출력할 수 있기 때문에 이러한 형태를 함수 표현식이라고 말한다.
함수 선언은 함수를 값으로 가지는 변수를 생성한다.
function functionDeclaration() { console.log("빵야!"); };위의 내용만을 가지고 콘솔에 값을 출력시키는 것은 불가능하다.
functionDeclaration()이라는 식을 만들어 사용해야 비로소 함수를 동작시킬 수 있다.이처럼 function 연산자를 사용해 선언하는 것을 함수 선언이라고 말한다.
📂 참고 자료
Array.prototype.map() - JavaScript | MDN
Array.prototype.reduce() - JavaScript | MDN
Array.prototype.filter() - JavaScript | MDN
JavaScript - setInterval, setTimeout 사용법
setInterval() - Web APIs | MDN
window.requestAnimationFrame() - Web API | MDN
자바스크립트 애니메이션 - requestAnimationFrame 활용하기
값 (컴퓨터 과학) - 위키백과, 우리 모두의 백과사전)
식 (프로그래밍) - 위키백과, 우리 모두의 백과사전)
문 (프로그래밍) - 위키백과, 우리 모두의 백과사전)