-
부트캠프 13일차에는 주어진 문제를 코딩하는 코플릿이나, 별도의 스프린트 없이 JS의 주요 개념인 원시/참조 자료형, 스코프, 클로저만 하루종일 학습하는 것으로 스케줄이 짜여있었다. 물론 학습한 것을 점검하는 문제가 있긴 했지만 코딩을 하거나 하는 것은 아니고 코드를 보고 4지선답형의 문제같은 것을 풀었다.
지난 2주 동안 HTML이나 CSS 등 기존에는 몰랐던 git 같은 부분도 학습을 다수 해왔는데 오늘은 자바스크립트와 관련된 심화 내용을 학습하였는데 개념적인 부분이 이렇게 어렵게 느껴지긴 처음이었다. 오늘 강의 이전에도 인터넷으로 클로저라는 용어는 자바스크립트와 관련하면 심심치 않게 등장해왔으므로 이에 대해서 스스로 알아보고자 시도한 적이 있긴 하였다. 하지만, 혼자서 영상을 찾아보고 글을 읽어도 도대체 클로저가 무엇인지 명확하게 정의되지 않는 느낌이 강하였는데 오늘은 하루종일 자바스크립트 관련된 개념들을 학습하면서 이에 대한 개념이 어느 정도 잡힌 듯한 느낌을 강하게 받을 수 있었다. 아무래도 오늘 중에는 학습한 내용이 다소 있어서 TIL에서는 간단하게 일부분만 정리하고 나중에 따라 해당 개념들만 따로 게시글을 올려야 될 듯 하다.
원시 자료형과 참조 자료형(Primitive type and Reference type)
코딩을 하면서 선언되는 변수들은 메모리에 저장된다. 이 때 변수가 저장될 때
let a = 1
과 같이 할당을 하게 되다면 나중에 변수를 불러올 때는a
라는 변수 명을 기준으로 거기에 할당되었던 1이라는 값을 불러올 수 있다. 이 때a
라는 변수명과 1이라는 값은 콜스택에 저장된다. 콜스택에 대해서는 나중에 개념 관련 게시물을 다룰 때 자세하게 다루도록 하겠다. 여기서 단순히 설명하면 콜스택이라는 데이터 저장소가 존재하며, 이 곳에 저장이 가능한 것은 원시 자료형 뿐이다. 원시 자료형은 number, string, boolean, null, undefined 이다.하지만 참조 자료형으로 할당된 값은 콜스택에 저장되지 않는다. 앞선 원시 자료형의 경우에는 하나의 변수에 하나의 값만 담을 수 있다. 반면 참조 자료형으로 분류되는 객체, 배열, 함수 등은 일반적으로 하나 이상의 값을 가지게 된다. (물론 비워놓을 수도 있지만 예외로 하자) 그렇기 때문에 참조 자료형의 값은 힙(heap) 이라는 별도의 데이터 보관함에 저장된다. 변수에는 데이터가 저장된 메모리 상의 참조 주소가 저장된다. 힙의 특성으로는 고정된 크기의 보관함이 아닌 동적으로 크기가 변하는 보관함으로 이해할 수 있다. 참조 자료형의 이름 참조는 이러한 특성으로 인해서 붙여진 것이다.
이러한 자료형의 자이와 관련해서 가볍게 생각하여 예시를 들면 스폰지밥과 징징이가 있다고 치자...
(너무 가볍나?)이 둘이 각자 신고 있던 신발을 신발장에 보관해야하는 상황이 생겼다. 이 때, 신발을 변수에 할당되는 값이라고 생각하고 신발장을 앞서 말한 콜스택이라고 생각하자 그리고 나중에 이 신발들을 신발장에서 꺼내기 위해서는 각자의 신발 위치를 식별할 무언가가 필요할 텐데 보통은 신발장에 이름을 붙일거다. 이 때 이름이 변수명이다. 그래서 신발장에 스폰지밥이 신발을 보관한다면 다음과 같이 코드로 나타낼 수 있을 것이다.
let spongeBob = '신발 1켤레'
스폰지밥은 자신의 신발 두 켤레(변수 값)를 신발장(콜스택)에 자신의 이름(변수명)을 적어 표시해두고 신발장에 보관했다. 징징이도 스폰지밥을 따라서 보관하려고 왔는데 문제가 있다. 징징이는 발이 6개다. (TMI: 징징이는 문어라고 스폰지밥 작가가 밝혔다.) 즉 보관할 신발이 1켤레가 아니고 3켤레다. 그런데 신발장 한 칸에는 최대 수용 용량이 신발 1켤레다. 그래서 신발장에 3개 칸을 쓰려고 하는데 이 신발장에는 같은 이름을 사용할 수 없다는 조건이 있다. (코드로 나타내면 아래와 같다)
// 신발장 칸을 3개 써야하나? let jingjingi = '신발 1켤레' let jingjingi = '신발 1켤레' let jingjingi = '신발 1켤레' //????? // => 신발장에는 같은 이름을 사용할 수 없다는 조건이 있다고 가정 // 배열로 표기하면 1개의 이름으로 신발을 보관할 수 있다. let jingjingi = ['신발 1켤레', '신발 1켤레', '신발 1켤레']
그래서 징징이는 한꺼번에 신발 3켤레(배열)를 보관하기 위해서 따로 직원이 있는 보관함에 신발을 맡겨야 한다. 이 직원이 있는 보관함을 힙이라고 가정하자. 그런데 이 보관함은 신발 켤레 수에 보관이 가능하지만 직원만 알아먹게끔 창고에 보관해서 나중에 징징이가 직접 신발을 찾기가 어렵다. 여기서 직원은 창고에 신발을 위치시킨 위치가 찍힌 보관증명서를 준다.
이제 그럼 참조 자료형이 그 값을 어떻게 나중에 불러오는지 위 사례에 맞춰서 설명할 수 있다. 다시 신발을 찾으러온 징징이(변수)는 자신이 가지고 있는 보관증명서(참조 자료형이 가지고 있는 힙의 주소) 를 건네준다. 그리고 그 보관증명서를 기준으로 창고 (힙) 에서 신발 6켤레(참조 자료형의 값)을 가져 올 수 있는 것이다.
실제로 코드를 작성할 때에 이러한 차이점으로 인하여 변수 간의 할당 등에서 일부 차이가 발생되는데 세부 케이스들을 열거하는 것은 나중에 따로 다시 다루게될 때 정리해보도록 하겠다.
스코프(Scope)
스코프는 정말 쉽게 말하면 범위를 말한다. 실제 영어 scope도 범위를 의미한다. 그치만 자바스크립트에서 적용되는 스코프는 물론 범위라는 의미를 가지지만 어떻게 적용되는 범위인지 이해하여야 적절한 변수 선언과 함수에서의 그 사용을 목표한 것처럼 이룰 수 있다.
[블록 스코프와 함수 스코프]
스코프에서 규칙이 다수 존재하긴 하는데 그것들을 먼저 이해하려면 블록 스코프와 함수 스코프의 정의는 사전에 이해하여야 한다. 사실 이 부분은 그렇게 크게 어렵지 않다. 우선 C-family language라는 것이 있는데 C라는 성공한 언어를 바탕으로 개발된 언어들이 이런 C의 가족 같은 개념으로 이들을 C-family language라고 부른다. 그에 해당되는 언어들은 요 링크에 리스트가 있다. 이들의 특성 중 하나는 블록이라는 개념이 있는데 이건 우리가 아는 curly brackety ({})로 둘러쳐진 부분을 말한다. 이 블록 안의 범위를 블록 스코프라고 한다. 그리고 선언된 함수에서 함수 안의 함수가 실행되는 내용을 담은 body의 범위가 함수 스코프다. 자바스크립트에서 잘 보면 함수가 실행될 내용도 {}으로 묶어져있다.
[전역 스코프와 지역 스코프]
흔히들 코딩에서 전역을 global, 지역을 local이라고들 많이 이야기 한다. 그럼 여기서 일단 지역을 알기전에 전역을 먼저 이해할 필요가 있다. 우리가 코드를 작성하는 제일 첫열 즉 들여쓰기 등이 없는 단계가 전역이다. 그리고 지역은 전역에서 들여쓰기가 들어가지고 국소적으로 이루어지는 부분을 지역이라고 한다. 다음 코드를 보자
let a = 1; function local() { let b = 2; console.log(b); }
우선 변수 a의 경우는 코드에서 들여쓰기가 없는 가장 왼쪽 첫열부터 시작한다. 이처럼 전역 스코프에서 선언된 변수를 전역 변수라고 한다. 반면에 함수 local 안에서 쓰인 변수 b는 들여쓰기가 없는 가장 바깥에서 선언된 것이 아닌 함수 안쪽에서 선언되었다. 이 함수 안의 범위는 지역 스코프로 칭하고 여기서 선언된 변수를 지역 변수라고 한다.
여기까지 이해하였다면 한가지 의문점이 생길 수 있다. 근데 그게 함수가 굴러가고 변수가 선언되는 와중에 전역이랑 지역을 나눠서 무슨 상관인가? 하고 생각할 수 있다. 위에 보여준 코드 처럼 변수가 서로 다른 이름을 가지고 선언되면 크게 이와 관련해 의문을 가질 필요가 없긴 하다. 하지만 아래와 같은 상황이라면 어떨까?
let a = 1; function local() { let a = 2; console.log(a); } local()
이전과 바뀐 부분은 함수 안의 지역 변수 이름이 a로 바뀌었다. 그리고 함수는 a의 값을 출력한다. 여기서 함수 local에서 출력하는 것은 전역 변수의 1일까? 지역 변수의 2일까? 정답은 2다. 함수 local은 자신의 지역에서 선언된 변수 a를 출력한다. 이는 스코프의 규칙 중에서 하나로 지역변수는 전역 변수보다 더 높은 우선 순위를 가진다는 점이 반영된 것이다. 이처럼 스코프의 개념을 모를 시에 왜 그런 것인지 혼동이 올 수 있는 부분이 존재한다.
[스코프의 정의]
보통은 뭘 하나 알려주기에 앞서서 정의를 적어두는데 나는 예시를 먼저보고 정의를 다시 보는 스타일이라 그냥 중간에 정의를 넣었다.
스코프는 "변수 접근 규칙에 따른 유효 범위"이다. 풀어 말하면 변수에 관련하여 변수의 값에 접근할 수 있는 규칙에 따라 변수 값에 접근이 가능한 유효 범위이다. 즉 내가 저기 함수에 쓰였던 변수를 끌어와서 다른 함수에 쓰고 싶은데 다른 함수에서 막 끌어와 사용할 순 없고 규칙에 따라야만 가능한데 이 규칙을 준수하면서 변수를 끌어올 수 있는 범위가 스코프다.
[스코프의 규칙]
총 3개 정도 있는 걸로 알고 있는데 나중에 더 있는 걸 알게되면 어차피 따로 스코프에 관한 글 다시 올릴거니깐 그 때 정리할거다.
1. 안쪽 스코프에서 바깥쪽 스코프로는 접근할 수 있지만 반대는 불가능
2. 스코프는 중첩이 가능하다.
3. 지역변수는 전역 변수보다 더 높은 우선 순위를 가진다.
클로저(Closure)
근래 학습한 개념 중에서 개인적인 주관으로 좀 악질적인 개념이다. 사실 클로저와 관련해서 정리한 게시물이나 영상들도 많으나 이걸 한줄로 표현 혹은 정의하자고 하면 다들 하는 말이 조금씩 다르다. 그래서 ECMAScript를 확인해보고자 했는데 어느 누군가는 클로저가 자바스크립트 고유의 것이 아니므로 그곳에도 정의되어 있지 않다고 한다. 일단 그 이야기를 보고 왠지 시간 낭비 될 것 같아서 내가 직접 확인 하는 것은 나중으로 미뤘다. 일단 구글에 검색해보면 mdn에서는 그것에 대해서 정의를 하고 있다. 하지만 직접 가서 정의를 확인해보면 무슨 말을 하는 것인지는 이해가 거의 되지 않는다. 사실 정의들이 모두 조금씩 다르고 그에 대한 설명도 다소 깊게 하는 경향이 있어 처음 학습할 때는 혼란스럽기만 하여 악질이라고 생각했다. 그런데 가만히 생각해보면 앞서서 스코프 개념을 이해하고 실행 컨텍스트의 개념을 알게되면 또 엄청 이해하기 어렵고 말도 안되는 개념은 아니다.
많은 사람들이 블로그 등에 포스팅한 것들을 바탕으로 정리해볼 때, 공통적으로 묘사하는 키워드가 있다. '내부 함수' , '외부 함수', '변수 접근' 이다. 그래서 일반적으로는 이렇게들 이야기를 많이 한다. '외부함수의 맥락(context), 변수에 내부 함수가 접근하는 것, 테크닉 등등' 여기서 공부하면서 열받는 부분이 무엇이냐면 정의라는 것의 마지막은 그것을 지칭하는 명사가 부여되어야 한다고 생각한다. 그런데 모두 종결하는 명사가 제각각이다. '~~하는 것', '~테크닉', '~환경' 등등 다양하다. 나는 그런데 이해하는 것에 있어서 처음에 이해하기 쉬운 것은 현상(situation)이라고 생각해서 우선은 하나의 현상으로 받아들이고 이해를 하기 시작했다.
클로저에 관한 부분을 이 포스팅에서 모두 서술하면 분량이 말도 안될 것 같아서 내가 생각하여 정의한 부분만 아래에 서술하고 다음에 기회가 되면 블로그에 별도로 클로저 관련된 내용을 포스팅하고자 한다.
[클로저의 정의]
클로저는 하나의 현상으로서 특정 함수(외부 함수)안에 선언된 내부 함수가 외부 함수의 변수에 접근하는 현상이다. 전역 스코프에서는 관여가 불가능한 함수의 변수에 접근함으로써 독립적, 폐쇄적인 변수 접근 환경을 구현한다.(closure = 폐쇄) 이러한 독립적 환경이라는 특성을 활용하여 모듈화에 유용한 특성을 가진다.
'개발학습 > 코드스테이츠 SE Bootcamp' 카테고리의 다른 글
코드스테이츠 SEB 15일차 TIL - DOM, DOM을 통한 HTML 조작 (0) 2021.08.08 코드스테이츠 SEB 14일차 TIL - JS Spread/Rest 문법, JS Koans (0) 2021.08.05 코드스테이츠 SEB 12일차 TIL - CSS 중급, 웹 앱 화면 설계 (0) 2021.08.03 코드스테이츠 SEB 11일차 TIL - JS 배열, 객체2 (0) 2021.08.02 코드스테이츠 SEB 10일차 TIL - JS 배열, 객체 (0) 2021.07.30 댓글