항해 99

항해99 - 2주차 후기

ble194 2022. 7. 19. 11:20

항해 2주차는 알고리즘 문제를 풀었다.

달리기반과 걷기반 문제가 있었는데

걷기반으로 선택을 했다.

 

처음에는 익숙하지 않은 아이들이라 어떤식으로 해가야 하는지 몰랐다.

특히 반복문은 사용은 하고 있지만 원리를 알지 못해서,

그 원리를 파악하는데 꽤 오랜시간이 걸렸다.

 

그래도 나름 흐름을 파악해서 이후에 알고리즘 푸는데에 많은 도움이 됐다.

또한 검색을 하면서 많은 메서드들을 접하고 활용하였는데,

메서드들이 해주는 역할을 파악하고 활용방법을 익혀서 살짝 어려운 문제도

메서드를 활용 할 수 있게 되었다.

 

알고리즘 문제에 메서드를 활용하면 푸는 의미가 없다는 의견이 얼핏들렸지만,

나는 메서드를 활용하는 방식으로 알고리즘을 푼 느낌이어서 많은 도움이 되었다.


[1] JavaScript의 자료형과 JavaScript만의 특성은 무엇일까 ?

Q1. 느슨한 타입(loosely typed)의 동적(dynamic) 언어를 알아보고 이 언어의 문제점은 무엇이고 보완할 수 있는 방법에는 무엇이 있을지 생각해보세요. 

 

A1. 우선 느슨한 타입의 동적언어라 함은 자바스크립트의 특징이다, c나 java같은 언어는 엄격한 타입의 언어인데 엄격한 타입의 언어들은 변수를 선언 할 때에 변수의 타입을 입력을 해주어야한다. 하지만 느슨한 타입의 언어는 변수 선언시에 타입을 생략하고 입력할 수 있다. 이 점은 입력하기 쉽게 만들어주는 장점이 있어서 빠른 속도가 날 수 있도록 도와주는 듯 하지만 반면에 규모가 큰 프로젝트를 진행할 때에는 타입이 다르게 입력되어 오류가 나는 경우가 있기 때문에 장점만 작용한다고 볼 수 없다. 이 장점을 보완하기 위해서는 타입스크립트를 사용하는 방법을 쓰는데, 타입스크립트는 자바스크립트의 타입을 확장하고 선언시 직접 알려주는 방법을 통해 변수에 타입을 선언할 수 있게한다.  


Q2. JavaScript 형변환을 알아봅시다.

 

A2. 자바스크립트는 타입이 매우 유연한 언어이다. 때문에 때로는 자바스크립트 엔진이 필요에 따라 ‘암시적변환’ 을 혹은 개발자의 의도에 따라 ‘명시적변환’ 을 실행 할 수 있다. 우선, 암시적 변환이란 자바스크립트 엔진이 필요에 따라 자동으로 데이터타입을 변환시키는 것이다. 암시적 변환을 보자면, 산술 연산자 중에서도
(1) 더하기 연산자(+)는 숫자보다 문자열이 우선시 되기때문에, 숫자형이 문자형을 만나면 문자형으로 변환하여 연산된다. (문자 > 숫자)
(2) 다른 연산자(-,*,/,%)는 숫자형이 문자형보다 우선시되기 때문에 더하기와 같은 문자형으로의 변환이 일어나지 않는다. (문자 < 숫자)

(3) 동치 비교 동치비교시 유의해야 할 점은 엄격하지 않은 동치 비교일 경우와 두 값을 비교할 때 데이터타입을 변환하지 않는 엄격한 동치(===) 비교와 혼동되지 않도록 한다.

다음으로 명시적변환이란 개발자가 의도를 가지고 데이터타입을 변환시키는 것이다. 타입을 변경하는 기본적인 방법은 `Object(), Number(), String(), Boolean()` 와 같은 함수를 이용하는데 new 연산자가 없다면 사용한 함수는 타입을 변환하는 함수로써 사용된다.


Q3. ==와  ===의 차이를 알아봅시다.


A3. ==는 예를 들어 "0"(문자열 0)과 0(숫자 0)을 타입에 상관없이 같은 취급을 한다. 하지만 ===는 타입까지 비교하여 형태가 다르면 같은 취급을 하지 않는다.


Q4. undefined와 null의 미세한 차이들을 비교해보세요.

 

A4. null과 undefined를 보이는 그대로 해석하면 ‘빈 값’과 ‘없는 값’을 의미하는 것처럼 보이지만 사실 큰 차이점이 있다.
(1) "공통점" - 둘다 각각의 타입명(undefined, null)의 값이 유일하다. (undefined 타입의 값은 undefined가 유일하다. null 타입의 값은 null이 유일하다.)
(2) "undefined 타입"

undefined는 원시 자료형 undefined로 분류된다. undefined는 ‘아무 값도 할당받지 않은 상태’를 의미한다. var 키워드로 선언한 변수는 암묵적으로 undefined로 초기화된다. 변수 선언에 의해 확보된 메모리 공간을 처음 할당이 이뤄질 때까지 빈 상태(*대부분 비어 있지 않고 쓰레기 값이 들어 있다.)로 내버려두지 않고 자바스크립트 엔진이 undefined로 초기화한다. 따라서 변수를 선언한 이후 값을 할당하지 않은 변수를 참조하면 undefined가 반환된다. 변수를 참조했을 때 undefined가 반환된다면 선언 이후 값이 할당되지 않은 즉, 초기화되지 않은 변수라는 것을 알 수 있다. 이처럼 undefined는 개발자가 의도적으로 할당하기 위한 값이 아니라 자바스크립트 엔진이 변수를 초기화 할 때 사용하는 값이다. 자바스크립트 엔진이 변수를 초기화라는 데 사용하는 undefined를 개발자가 의도적으로 변수에 할당한다면 undefined의 본래의 취지와 어긋나고 또한 혼란을 야기하므로 권장하지 않는다. 그렇다면 변수에 값이 없다는 것을 명시하고 싶을 때는 어떻게하면 좋을까? 바로 undefined를 할당하는 것이 아니라 null을 할당한다. undefined를 직역하면 ‘정의되지 않은’이란 의미이다. 자바스크립트 undefined에서 말하는 정의란 ‘변수의 값을 할당하여 변수의 실체를 명확히 하는 것’를 의미한다. 자바스크립트의 경우 변수를 선언하면 암묵적으로 정의가 이뤄지기 때문에 선언과 정의의 구분이 모호하다. ECMAScript 사양에서 변수는 ‘선언한다.’라고 표현하고, 함수는 ‘정의한다.’라고 표현한다.
(3) "null 타입"
null은 원시 자료형 null로 분류된다. 자바스크립트는 대소문자를 구분하므로 null은 Null, NULL 등과는 다르다. null은 ‘비어있는, 존재하지 않는 값'(값의 부재)을 의미한다. 프로그래밍 언어에서 null은 변수에 값이 없다는 것을 의도적으로 명시(의도적 부재)할 때 사용한다. 변수에 null을 할당하는 것은 변수가 이전에 참조하던 값을 더 이상 참조하지 않겠다는 의미이다. 이는 이전에 할당되어 있던 값에 대한 참조를 명시적으로 제거하는 것을 의미하며, 자바스크립트 엔진은 누구도 참조하지 않은 메모리 공간에 대해 *가비지 컬렉션을 수행할 것이다.
*가비지 컬렉션은 프로그램에서 더 이상 사용하지 않는 메모리를 자동으로 정리하는 것이다.


[2] JavaScript 객체와 불변성이란 ? 

Q1. 기본형 데이터와 참조형 데이터의 비교 //추가 공부 필요


A1. 데이터 타입의 종류는 크게 기본형과 참조형 2가지로 나뉜다.
기본형과 참조형을 구분 짓는 가장 큰 점은 실제 값 전체 복사 vs 실제 값이 들어있는 주소 값 복사이다.
(기본형 데이터)가 저장될 때는 아래와 같은 순서로 저장된다. 

(1) 변수 영역에서 빈 공간(@1003 : 임의의 주소 값)을 확보한다. 
(2) 확보한 공간의 식별자(변수명)를 a로 지정한다. 
(3) 일단 데이터 영역에서 1을 찾고, 없으면 데이터 공간을 하나 만들어(@5004)에 숫자 1을 저장한다. 
(4) 변수 영역에서 a라는 식별자를 검색한다.(@1003).
(5) 앞서 저장한 문자열의 주소(@5004)를 @1003의 공간에 연결한다. a += 10 코드 처리
(6) 1이 저장된 공간에 11을 할당하는 대신 데이터 영역에서 11을 찾고, 없으면 새로 만들어 별도의 공간에 저장한다. 
(7) 그 주소를 1003의 공간에 연결한다. 
위의 처리 과정에서 한 번 만든 값은 다른 값으로 변경되지 않는다. 대신 새로 만드는 과정을 통해서만 변경이 일어나고 있다. 이것이 불변값(immutable)의 성질이다. 한 번 만들어진 값은 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않는다.
(참조형 데이터)가 저장될 때는 아래와 같은 순서로 저장된다. 
(1) 변수 영역에서 빈 공간(@1002 : 임의의 주소 값)을 확보한다. 
(2) 확보한 공간의 식별자(변수명)를 a로 지정한다. 
(3) 임의의 데이터 저장 공간(@5001) 에 데이터를 저장하려고 보니 여러 개의 프로퍼티로 이뤄진 데이터 그룹이다. 이 그룹 내부의 프로퍼티(x) 들을 저장하기 위해 별도의 변수 영역을 마련하고, 그 영역의 주소(@7103~ ?)를 @5001에 저장한다. 
(4) @7103 에 x라는 프로퍼티 이름을 지정한다. 
(5) 데이터 영역에서 숫자 1을 검색하고 없으면, 임의로 @5003에 저장하고, 이 주소를 다시 @7103에 저장한다. 
a.x += 10 코드 처리
(6) 데이터 영역에서 숫자 11을 검색한다. 검색 결과가 없으면 빈 공간인 @5005에 저장하고 그 주소를 @7103에 저장한다. 
위의 처리 과정에서 10을 더하기 전과 더한 후 변수 a가 바라보고 있는 주소는 여전히 @5001로 변하지 않는 것을 볼 수 있다. 즉 '새로운 객체'가 만들어진 것이 아니라 기존의 객체 내부의 값만 1에서 11로 바뀐 것이다. 데이터 영역에 저장된 값은 모두 불변값이지만(1,11), 변수(@7103)에는 다른 값을 얼마든지 대입할 수 있다. 이것을 가변값(mutable)이라고한다.
*그렇다면 왜 참조형은 주소 값을 복사하는 것일까? 항상 그렇듯 성능의 문제이다. 참조형에는 어떤 값이 들어갈지 모른다. 그 말인즉슨, 주소 값이 아닌 값 전체를 복사하게 되면 용량이 어마어마하게 커질 수도 있다는 뜻이다. 

✅ 기본형 데이터 (primitive type)                           
- Number                                                                                                 
- String                                                                                            
- Boolean                                                                                            
- Null                                                                                                
- Undefined                                                                                 
- Symbol                                                                                                  
- .etc

✅ 참조형 데이터(reference type)
- Object
- Array
- Function
- Date
- regexp
- Map, WeakMap
- Set, WeakSet


Q2. 불변 객체를 만드는 방법

 

A2. 먼저 불변(immutability)이란 뭘까? 단어에서 유추해볼 수 있다시피 '변하지 않는' 뜻이라고 생각하면 되겠다.
그럼 '불변 객체'란? '변하지 않는 객체' 즉 이미 할당된 객체가 변하지 않는다는 뜻을 가지고 있다.
자바스크립트에서 불변 객체를 만들 수 있는 방법은 기본적으로 2가지 인데 const와 Object.freeze()를 사용하는 것이다.
(1) const
자바스크립트 키워드 중 하나인 const이다. ES6문법부터 let과 const를 지원한다. const 키워드는 변수를 상수로 선언할 수 있다, 일반적으로 상수로 선언된 변수는 값을 바꾸지 못하는 것으로 알려져 있다. 그렇다면 상수로 선언한 객체는 불변 객체일까? const 키워드로 선언된 test변수에는 객체 재할당은 불가능하지만 객체의 속성은 변경 가능하다. 재할당이 불가능 한 이유는 변수와 값(객체) 사이의 바인딩 자체가 변경이 되기 때문에 상수인 test변수는 재할당이 불가능한 것이고 객체의 속성이 변경가능 한 이유는 실제 객체가 변경은 되지만 ( {} -> name : "mingyo" ) 객체와 변수(test)사이의 바인딩은 변경이 되지 않기 때문에 객체의 속성은 변경가능한 것이다.  때문에 비록 재할당은 불가능하지만 객체의 속성을 변경함으로 인해 변수에 바인딩된 객체의 내용까지 변경이 되기 때문에 불변객체라고 하기는 힘들다. 따라서 Object.freeze()라는 JS내장메소드도 살펴보도록 하겠다.
(2) Object.freeze()
자바스크립트에서 기본적으로 제공하는 메소드인 Object.freeze() 메소드이다. 공식 문서에서는 "객체를 동결하기 위한 메소드" 라고 적혀있다. 그렇다면 이 메소드를 사용하면 불변 객체를 만들 수 있을까?먼저 이 메소드의 사용법부터 알아보면, 사용법은 간단하다. test 변수에 key value를 가진 객체를 바인딩 후 Object.freeze(test)를 사용해 바인딩된 변수를 동결 객체로 만들었다. 때문에 test 객체는 객체의 속성을 변경하는 시도는 불가능하다. 그러나 Object.freeze()는 동결된 객체를 반환하지만 객체의 재할당은 가능하다. 그럼 결국 불변 객체는 어떻게 만들 수 있냐면 const와 Object.freeze()를 조합하여 만들 수 있다. (const의 재할당불가 + Object.freeze()의 객체속성 변경불가) 먼저 const키워드로 바인딩 된 변수를 상수화 시킨 다음, Object.freeze()로 해당 변수를 동결 객체를 만들면 객체의 재할당과 객체의 속성 둘 다 변경불가능한 불변 객체가 된다.


Q3. 얕은 복사와 깊은 복사


A3. 결론부터 말하자면 얕은 복사는 객체의 참조값(주소 값)을 복사하고, 깊은 복사는 객체의 실제 값을 복사합니다.  먼저, 자바스크립트에서 값은 원시값과 참조값 두 가지 데이터 타입의 값이 존재합니다. *원시값은 기본 자료형(단순한 데이터)을 의미합니다.  Number, String, Boolean, Null, Undefined 등이 해당합니다. 변수에 원시값을 저장하면 변수의 메모리 공간에 실제 데이터 값이 저장됩니다. 할당된 변수를 조작하려고 하면 저장된 실제 값이 조작됩니다. *참조값은 여러 자료형으로 구성되는 메모리에 저장된 객체입니다. Object, Symbol 등이 해당합니다. 변수에 객체를 저장하면 독립적인 메모리 공간에 값을 저장하고, 변수에 저장된 메모리 공간의 참조(위치 값)를 저장하게 됩니다. 그래서 할당된 변수를 조작하는 것은 사실 객체 자체를 조작하는 것이 아닌, 해당 객체의 참조를 조작하는 것입니다.  원시값을 복사할 때 그 값은 또 다른 독립적인 메모리 공간에 할당하기 때문에, 복사를 하고 값을 수정해도 기존 원시값을 저장한 변수에는 영향을 끼치지 않습니다. 이처럼 실제 값을 복사하는 것을 깊은 복사라고 합니다. 하지만 이것은 자료형을 깊은 복사한 것입니다. 참조값을 복사할 때는 변수가 객체의 참조를 가리키고 있기 때문에 복사된 변수 또한 객체가 저장된 메모리 공간의 참조를 가리키고 있습니다. 그래서 복사를 하고 객체를 수정하면 두 변수는 똑같은 참조를 가리키고 있기 때문에 기존 객체를 저장한 변수에 영향을 끼칩니다. 이처럼 객체의 참조값(주소값)을 복사하는 것을 얕은 복사라고 합니다.  일반적으로 복사라는 개념을 생각한다면 깊은 복사가 떠오를 것입니다. 하지만 객체를 복사할 때  =  키워드를 사용해서 복사하면 얕은 복사가 돼서 기존 변수 또한 수정돼서 당황하게 될 겁니다. 그렇다면 자바스크립트에서 얕은 복사 혹은 깊은 복사를 하는 방법은 어떤 것이 있을까요?
1. 얕은 복사(shllow Copy) 방법
얕은 복사란 객체를 복사할 때 기존 값과 복사된 값이 같은 참조를 가리키고 있는 것을 말합니다. 객체 안에 객체가 있을 경우 한 개의 객체라도 기존 변수의 객체를 참조하고 있다면 이를 얕은 복사라고 합니다.
(1) Array.prototype.slice()
얕은 복사 방법의 대표적인 예라고 할 수 잇습니다. start부터 end 인덱스까지 기존 배열에서 추출하여 새로운 배열을 리턴하는 메소드 입니다. 만약 start와 end를 설정하지 않는다면, 기존 배열을 전체 얕은 복사합니다. 기존 배열에는 영향을 끼치지 않아서 깊은 복사로 보일 수 있지만, 원시값을 저장한 1차원 배열일 뿐입니다. 원시값은 기본적으로 깊은 복사입니다. Slice() 메소드는 기본적으로 얕은 복사를 수행합니다.  만약 1차원 배열이 아닌 중첩 구조를 갖는 2차원 배열이면 얕은 복사를 수행하게 됩니다. 배열 안에 객체를 수정하고자 할 경우 얕은 복사를 수행하는 것을 볼 수 있습니다. 하지만 원시값은 기본적으로 깊은 복사라 기존 변수에 있는 값과는 다른 값을 도출하는 것을 볼 수 있습니다. 
(2) Object.assign(생성할 객체, 복사할 객체)
메소드의 첫 번째 인자로 빈 객체를 넣어주고 두 번째 인자로 복사할 객체를 넣어주면 됩니다. 복사된 객체 copy 자체는 기존 object와 다른 객체지만 그 안에 들어가 있는 값은 기존 object안의 값과 같은 참조 값을 가리키고 있습니다. 깊은 클로닝에 대해서, Object.assign() 은 속성의 값을 복사하기때문에 다른 대안을 사용해야합니다. 출처 값이 객체에 대한 참조인 경우, 참조 값만을 복사합니다.
(3) Spread 연산자 (전개 연산자)
마찬가지로 얕은 복사입니다.
2. 깊은 복사(Deep Copy) 방법
깊은 복사된 객체는 객체 안에 객체가 있을 경우에도 원본과의 참조가 완전히 끊어진 객체를 말합니다.
(1) JSON.parse && JSON.stringify
JSON.stringify()는 객체를 json 문자열로 변환하는데 이 과정에서 원본 객체와의 참조가 모두 끊어집니다. 객체를 json 문자열로 변환 후, JSON.parse()를 이용해 다시 원래 객체(자바스크립트 객체)로 만들어줍니다. 이 방법이 가장 간단하고 쉽지만 다른 방법에 비해 느리다는 것과 객체가 function일 경우,  undefined로 처리한다는 것이 단점입니다.
(2) 재귀 함수를 구현한 복사 / 복잡하다는 것이 단점입니다.
(3) Lodash 라이브러리 사용 / 라이브러리를 사용하면 더 쉽고 안전하게 깊은 복사를 할 수 있습니다. 설치를 해야 한다는 점과 일반적인 개발에는 효율적이겠지만, 코딩 테스트에는 사용할 수 없다는 것이 단점입니다.


[3] 호이스팅과 TDZ는 무엇일까 ?

Q1. 스코프, 호이스팅, TDZ


A1. 스코프, 호이스팅, TDZ

1. 스코프

식별자에 대한 유효 범위입니다.함수 내부에서 선언한 변수는 함수 내부에서만 사용 가능합니다. 글로벌 변수와 지역 변수에 대해 공부하면서 이 개념에 대해 얼핏 감을 잡아본 경험이 있을 것입니다. 이런 스코프 개념은 JS뿐만 아니라 python, C 등 거의 모든 언어에서 해당되는 개념입니다.자바스크립트의 스코프는 함수 레벨 스코프를 따른다. 같은 함수 레벨에 존재하면 값을 참조할 수 있다는 건데 ES6에서 let 키워드가 도입되면서 블록 레벨 스코프를 사용할 수 있게 됐습니다.
(1) 전역 스코프
어디서든 참조 가능전역 변수 전역 스코프를 갖는 전역 변수 어디서든 참조 가능 지역 스코프 함수 자신과 하위 함수에서만 참조 가능
(2)지역 스코프를 갖는 지역 변수
함수 내에서 선언된 변수로 해당 함수와 해당 함수의 하위 함수에서 참조 가능 암묵적 전역 변수 선언하지 않은 변수에 값을 할당하면 전역 객체의 프로퍼티가 되어 전역 변수처럼 동작한다.하지만 변수 선언이 없었기 때문에 호이스팅은 발생하지 않는다.
2. 호이스팅
함수의 코드를 실행하기 전에 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것. 초기화를 제외한 선언만 호이스팅. 그렇기 때문에 선언, 정의된 코드보다 호출하는 코드를 먼저 배치할 수 있음. 변수의 선언과 초기화를 분리. 변수의 선언을 코드의 최상단으로 끌어올림. 변수 선언 형식에 따른 초기화 var : 호이스팅 시 undefined로 변수를 초기화 function : 선언된 위치와 상관없이 동일하게 호출 let, const : 호이스팅 시 변수를 초기화하지 않음. (호이스팅 대상은 맞음)
3. TDZ(Temporal Dead Zone, 일시적 사각지대)
TDZ의 영항을 받는 구문 const, let, class 변수 스코프의 맨 위에서부터 ~ 변수의 초기화 완료 시점까지의 변수는 TDZ에 들어간 변수 코드의 작성 순서(위치)가 아니라 코드의 실행 순서(시간)에 의해 형성 let 변수 선언 코드가 그 변수에 접근하는 함수보다 아래에 위치하지만 함수의 호출 시점이 사각지대 밖이므로 정상 동작. 부모 클래스를 상속받을 경우, 생성자 안에서 super()호출을 하기 전까지 this바인딩은 TDZ안에 있다. 결론, TDZ는 선언 전에 변수를 사용하는 것을 허용하지 않는다. var의 사용은 의도치 않은 중복선언과 재할당으로 문제가 생길 수 있기 때문에 사용하지 않는편이 좋다.


Q2. 함수 선언문과 함수 표현식에서 호이스팅 방식의 차이

 

A2. 함수 선언식은 함수 전체를 호이스팅 합니다. 정의된 범위의 맨 위로 호이스팅되서 함수 선언 전에 함수를 사용할 수 있다는 것입니다.
함수 표현식은 별도의 변수에 할당하게 되는데, 변수는 선언부와 할당부를 나누어 호이스팅 하게 됩니다. 선언부만 호이스팅하게 됩니다. 함수 표현식은 호이스팅이 안되는 느낌입니다.


Q3. 실행 컨텍스트와 콜 스택 //추가 공부 필요


A3. 실행 컨텍스트와 콜 스택

1. Execution context(실행 컨텍스트)
자바스크립트 코드가 실행되는 환경을 의미한다. 자바스크립트에서 대표적으로 두 가지 타입의 Execution context가 있다. 실행할 코드에 제공할 환경 정보들을 모아놓은 객체들로 자바스크립트의 동적 언어로서의 성격을 가장 잘 파악할 수 있는 개념이다.
(1) Global Execution context
자바스크립트 엔진이 처음 코드를 실행할 때 Global Execution Context가 생성된다. 생성 과정에서 전역 객체인 Window Object (Node는 Global) 를 생성하고 this가 Window 객체를 가리키도록 한다.
(2) Function Execution context
자바스크립트 엔진은 함수가 호출 될 때마다 호출 된 함수를 위한 Execution Context를 생성한다.
모든 함수는 호출되는 시점에 자신만의 Execution Context를 가진다.
자바스크립트는 실행 컨텍스트가 활성화되는 시점에 다음과 같은 현상이 발생한다.
2. call stack
코드가 실행되면서 생성되는 Execution Context를 저장하는 자료구조, 엔진이 처음 script를 실행할 때, Global Execution Context를 생성하고 이를 Call Stack에 push한다. 그 후 엔진이 함수를 호출할 때 마다 함수를 위한 Execution Context를 생성하고 이를 Call Stack에 push 한다. 자바스크립트 엔진은 Call Stack의 Top에 위치한 함수를 실행하며 함수가 종료되면 stack에서 제거(pop)하고 제어를 다음 Top에 위치한 함수로 이동한다. 1줄 요약 : 프로그램이 함수 호출을 추적할때 사용한다.

Q4. 스코프 체인, 변수 은닉화


A4. 스코프 체인, 변수 은닉화

1. 스코프 체인
스코프를 안에서 부터 바깥으로 차례대로 검색해 나가는 것 '스코프 체인'이라고 합니다. 이를 가능케 하는 것이 LexiclaEnvironment의 두 번째 수집 자료인 outerEnvironmentReference입니다. outerEnvironmentReference은 현재 호출된 함수가 선언될 당시의 LexiclaEnvironment를 참조합니다. 앞서 실행 컨텍스트에서 살펴보았듯 LexiclaEnvironment가 만들어지는 것은 어떤 실행 컨텍스트가 활성화된 상태일 뿐입니다. 말이 좀 어려운데 차례대로 정리하면 이렇습니다. a 함수 내부에 b 함수를 선언하고 b 함수 내에 c 함수를 선언한 경우 함수 c의 outerEnvironmentReference는 함수 b의 LexiclaEnvironment를 참조합니다. 함수 b의 outerEnvironmentReference는 함수 a의 LexiclaEnvironment를 참조합니다. 처음 선언된 함수 a의 outerEnvironmentReference는 전역 객체의 LexiclaEnvironment를 참조합니다. 이러한 구조는 연결 리스트(linked list)의 자료 구조형임을 알 수 있습니다. 따라서 가장 가까운 요소부터 차례대로만 접근할 수 있고 다른 순서로 접근하는 것은 불가능합니다. 따라서 동일한 식별자를 선언한 경우에는 스코프 체인 상에서 가장 먼저 발견된 식별자에게만 접근 가능합니다. 순차적으로 변수에 할당된 값이 없으면 가까운 스코프부터 확장해 나가면서 값을 찾습니다. 주의할 점은 스코프 체인에서 밖으로 스코프를 늘려나갈 수는 있지만 내부로 돌아갈 수는 없다는 것입니다. 
2. 변수 은닉화
스코프 이하에 있는 스코프들은 전역 변수에 접근할 수 없게 됩니다. 이러한 기법을 '변수 은닉화'라고 합니다.


[4] 실습 과제

Q. 콘솔에 찍힐 b 값을 예상해보고, 어디에서 선언된 “b”가 몇번째 라인에서 호출한 console.log에 찍혔는지, 왜 그런지 설명해보세요. 주석을 풀어보고 오류가 난다면 왜 오류가 나는 지 설명하고 오류를 수정해보세요.

let b = 1;   //1

function hi () {

const a = 1;

let b = 100;

b++;

console.log(a,b); //2

}

//console.log(a);

console.log(b); //함수를 열 수 없어서 1의 값을 가져왔다.

hi(); //함수를 실행하여 2의 값을 가져왔다.

console.log(b); //함수를 열 수 없어서 1의 값을 가져왔다.



- 출처 -