본문 바로가기
내일배움캠프 TIL

2023-10-13 본 캠프 7일차 / 26일차 TIL

by KMS_99 2023. 10. 14.

2023-10-13 본 캠프 7일차 / 26일차 TIL

   
유데미 강의 : CSS 완벽가이드 (Flex, Grid & Sass) / 섹션 8: 크기 & 단위

* 학습시간  07:30 ~ 09:30 (2시간)

 

학습내용 :

 

1. em & rem

- em, rem은 font-size에 국한되어 사용되진 않지만, 그 기준은 font-size에 있다.
- 브라우저의 폰트 크기 설정에 따라서 크기가 유동적으로 변경됨.
    * 크롬 기준 Small, Middle, Large
- em은 이전 부모의 크기를 상속
    * 누적이 되어 상속되는 점을 고려해야함. 
    * 누적이 되는 문제는 rem으로 해결가능
    * em은 자식 요소에만 사용하는 것을 권장. (누적사용 x)
- rem은 root em으로 가장 상위의 html요소의 font-size를 기준으로 함.
    * rem은 상속이 누적되는 문제가 없기 때문에 em보다 권장한다.
- margin과 padding도 rem으로 설정하여 동적으로 사용할 수 있다.
    * margin과 padding은 크기 설정 단위를 통일하는 것이 좋다.
- box-shadow, border, border-radius와 같은 특성은 고정적인 px 단위를 사용하는 것이 좋다.

 


2. vw & vh

- vw와 vh 는 백분율의 단위를 가진다. 즉 0 ~ 100의 값을 갖는다.
- vw와 vh는 조상요소를 기준으로하는 %와 다르게 항상 viewport의 크기를 기준으로 한다.
- vmin은 현재 viewport상 width, height 중 더 작은 크기를 기준으로 한다.
- vmax는 현재 viewport상 width, height 중 더 큰 크기를 기준으로 한다.
- position : fixed 와 %, vw&wh를 이용하면 화면 전체에 덮는 효과를 줄 수 있다.
- windows 환경에서는 vw : 100 속성을 사용하였을 때 가로 스크롤이 발생하는 문제가 있다.
해당 문제는 windows에서 viewport를 스크롤을 포함하지 않아서 발생한다.
이를 해결하는 방법에는
    1. width : 100% 활용하기
    2. body에 overflow-x : hidden 속성 추가
    3. ::-webkit-scrollbar 의사 요소 추가 (비표준 기능)
        * 스크롤바의 스타일을 지정
        * 스크롤바의 width를 0으로 주면서 없애기

body::-webkit-scrollbar{
	width:0
}


√ tip. 가운데 정렬
margin : auto
* 너비가 명시된 블록레벨 요소 내의 자식요소를 가운데 정렬할 때 사용


내일배움캠프 : JavaScript 문법 종합반 2, 3주차

* 학습시간   09:30 ~ 12:20, 13:00 ~ 14:30 19:00~21:00 (7시간 30분)

 

학습내용 :

2주차 1, 2강 : ES6 문법 소개 및 실습

 

ES6란?

2015년에 발표된 자바스크립트 버전으로 대규모 문법적 향상 및 변경이 이루어졌다.




1. let const


- 이전에는 var라는 키워드로 변수 생성, 재할당과 재선언이 가능함. 
- ES6에서는 변수 선언방식으로 let과 const가 추가되었다.

var varValue = 1; 
varValue = 2;
var varValue = 3; 

let letValue = 1;
letValue = 2; // 재할당 가능
// let letValue = 3; // SyntaxError (재선언 불가능)

const constValue = 1;
// constValue = 2; // SyntaxError (재할당 불가능)
// const constValue = 3; // SyntaxError (재선언 불가능)

 

2. 화살표 함수 (Arrow Function)


- 기존에는 함수 선언문, 함수 표현식로 함수를 정의
- ES6에서는 화살표 함수라는 함수 선언방식이 추가되었다.

 

// 1. 기존 방식
// 함수 선언문
function add(a, b) {
    return a + b;
}
// 함수 표현식
let add2 = function(a, b){
    return a + b;
}
// 2. ES6 신 문법 화살표함수 (간단할 경우 한줄로 표현도 가능)
let add3 = (a, b) => {
    return a + b
}

 

3. 삼항 연산자


- 간단한 조건문을 한줄로 나타낼 때 사용한다.

console.log(true ? '참' : '거짓'); // 참
console.log(false ? '참' : '거짓'); // 거짓

 

4. 구조 분해 할당 (destructuring)


- 하나의 변수에 여러 값을 가지고 있는 데이터 타입인 배열과 객체에서 각 값들을 분해하는 구조분해할당 문법이 추가되었다.

4-1. 배열

// 4-1. 배열
let [value1, value2] = [1, 'new'];
console.log("value1 : ", value1); // value1 :  1
console.log("value2 : ", value2); // value2 :  new

let arr = ['value1', 'value2', 'value3'];

// 인덱스 순서대로 할당
let [a, b] = arr; 
console.log("a : ", a); // a :  value1
console.log("b : ", b); // b :  value2

// 초과된 변수에는 undefined 할당
let [a1, b1, c1, d1] = arr;
console.log("a1 : ", a1); // a :  value1
console.log("b1 : ", b1); // b :  value2
console.log("c1 : ", c1); // c :  value3
console.log("d1 : ", d1); // c :  undefined

// 값이 들어오지 않을 경우를 대비하여, 초기값 세팅가능
let [a2, b2, c2, d2='initValue'] = arr;
console.log("a2 : ", a2); // a :  value1
console.log("b2 : ", b2); // b :  value2
console.log("c2 : ", c2); // c :  value3
console.log("d2 : ", d2); // c :  defaultValue

4-2. 객체

// 4-2. 객체
// 배열의 구조분해할당과는 다르게 키값으로 값을 매칭하여 가져온다.
let user = {
    name : 'kim',
    age : 30,
};

// 키와 저장할 변수의 이름을 같게 설정
let {name, age} = user;
console.log('name => ', name); // name =>  kim
console.log('age => ', age); // age =>  30

// 키와 저장할 변수의 이름을 다르게 설정
let {name: newName, age: newAge} = user; 
console.log('newName => ', newName); // newName =>  kim
console.log('newAge => ', newAge); // newAge =>  30

// 없는 키를 저장하려고 할 때
let {name: name1, age: age1, birthday1} = user;
console.log('name1 => ', name1); // name1 =>  kim
console.log('age1 => ', age1); // age1 =>  30
console.log('birthday1 => ', birthday1); // birthday1 => undefined

// 없는 키를 저장할 때를 대비한 초기값 설정
let {name: name2, age: age2, birthday2='today'} = user;
console.log('name2 => ', name2); // name2 =>  kim
console.log('age2 => ', age2); // age2 =>  30
console.log('birthday2 => ', birthday2); // birthday2 => undefined

 

5. 단축 속성명


- key와 value를 담은 변수의 이름이 같을 때 key:value의 형태를 key(value)와 같이 한번만 써준다.

const name = 'kim';
const age = '24';

// 두개의 객체는 같은 값의 형태를 띈다.
const user = {
    name: name,
    age: age,
};

const user1 = {name,age,};
console.log (user); // { name: 'kim', age: '24' }
console.log (user1); // { name: 'kim', age: '24' }

 

6. 전개 구문 (spread operator)


- 배열과 객체와 같이 여러 값을 포함하고 있는 데이터 타입의 여러 값을 묶여있는 형태가 아닌 풀어서 전개한다.

 

6-1. 배열에서의 전개구문

// 6-1. 배열에서의 전개구문
let arr = [1, 2, 3];
console.log(arr); // [ 1, 2, 3 ]
console.log(...arr); // 1 2 3, 요소를 풀어서 전개

let arr1 = [...arr, 4];
console.log(arr1); // [1, 2, 3, 4]

6-2. 객체에서의 전개구문

// 6-2. 객체에서의 전개구문
let member = {
    name : 'kim',
    age : 24.
};

let member2 = {...member};
console.log(member) //{ name: 'kim', age: 24 }
console.log(member2) //{ name: 'kim', age: 24 }

 

 

7. 나머지 매개변수 (rest parameter)


- 초과된 매개변수를 관리하는 변수 

function exampleFunc (a, b, c, ...args) {
    console.log(a, b, c);
    console.log(args);
}

exampleFunc(1, 2, 3, 4, 5);

 

8. 템플릿 리터럴

// 8-1. 문자열 값을 나타내는 기존 방법
console.log('Hello World'); // (' ') 작은따옴표
console.log("Hello World"); // (" ") 큰따옴표

// 8-2. 문자열 값을 나타내는 추가 방법
const caption ='!!';
console.log(`Hello World`); // (` `) 백틱
console.log(`Hello World${caption}`); // 자바스크립트와 연결가능
console.log(`
    Hello 
        World
            ${caption}
`); // 멀티라인 지원

2주차 3, 4강 : 일급 객체로서의 함수

 

일급객체

First-class Object, 다른 객체들과 일반적으로 같은 기능을 가지고 있는 객체



함수는 일급객체이기 때문에 유연한 활용이 가능하다.

 

일급객체로서 함수가 가지는 특징

 

1. 변수에 함수를 할당할 수 있다.
- 함수가 마치 값으로 취급된다.
- 함수가 나중에 재사용이 가능하다.

const sayHello = function(){
    console.log('Hello!');
}

 

2. 함수를 인자로 다른 함수로 전달가능하다. (콜백함수)
- 콜백함수 : 매개변수로서 쓰이는 함수

function callFunction(func) {
    // 매개변수로 받은 변수가 함수다.
    func();
}

callFunction(sayHello);

 

3. 함수를 반환할 수 있다. (고차함수)
-고차함수 : 함수를 인자로 받거나 return하는 함수

function createAdder (num) {
    return function(x) {
        return x+num;
    }
}

const addFive = createAdder(5);
// 다음과 같은 의미이다. 
// const addFive = function(x){
//     return x+5;
// };

console.log(addFive(10)); // 15

 

4. 프로퍼티로 함수를 사용할 수 있다.
- 메서드 : 객체의 프로퍼티로 함수가 오는 경우

const person = {
    name : 'John',
    age : 31,
    isMarried: true,
    // 일반적인 메서드의 형태
    sayHello : function(){
        console.log(`${this.name}님이 인사하셨습니다.`);
    },
    // 화살표 함수에서는 this 키워드가 항상 전역객체를 가리킨다.
    // 따라서 메서드로서 객체 내부의 값에 접근할 수 없다.
    sayBye : ()=>{
        console.log(`${this.name}님이 나가셨습니다.`);
    }
}

person.sayHello(); //John님이 인사하셨습니다.
person.sayBye(); //undefined님이 나가셨습니다.

 

5. 배열의 요소로 함수를 할당할 수 있다.

const myArr = [
    function (a,b) {
        return a+b;
    },
    function (a,b) {
        return a-b;
    },
];

// 더하기
console.log(myArr[0](1,3)); // 4
// 빼기
console.log(myArr[1](3,1)); // 2

2주차 5, 6강 : Map/Set 소개 및 예시코드 연습

 

JavaScript는 객체와 배열을 통해 많고 다양하고 복잡한 프로그램을 만들어왔다.
하지만 현실세계를 반영하기에는 어려움이 있었다.
따라서 Map, Set 이라는 추가적인 자료구조가 등장하였다.

 

Map, Set의 목적 : 기존의 객체나 배열보다 데이터의 구성, 검색, 사용을 효율적으로 처리

 

1. Map

 

- key / value pair
- key에 어떤 데이터타입 (유형)도 다 들어올 수 있다.
- Map은 Key가 정렬된 순서로 저장된다.
- 기능 : 검색, 삭제, 제거, 여부확인
- 대량데이터 처리에 유용

 

Map - JavaScript | MDN

Map 객체는 키-값 쌍과 키의 원래 삽입 순서를 기억합니다. 모든 값(객체 및 원시 값 모두)은 키 또는 값으로 사용될 수 있습니다.

developer.mozilla.org

// 생성자 함수를 통한 생성
const myMap = new Map();

// 등록
myMap.set('one', 1);
myMap.set('two', 2);
myMap.set('three', 3);

// 검색
console.log(myMap.get('one')); // 1
console.log(myMap.get('two')); // 2
console.log(myMap.get('three')); // 3

// 반복 for ~ of ~ / 메서드 => keys(모든키), values(모든값), entries(모든키/값의 쌍)
// Iterator 속성을 가지고 있기 때문에 반복(순회) 가능하다.
for (const key of myMap.keys()){
    console.log(`keys() => ${key}`);
}

for (const value of myMap.values()){
    console.log(`values() => ${value}`);
}

for (const [key, value] of myMap.entries()){
    console.log(`entries() => ${key} : ${value}`);
}

// Map 크기
console.log(myMap.size); // 3

// Map의 key 기반 검색
console.log(myMap.has("two")); //true
console.log(myMap.has("five")); //false

 

2. Set

 

- 고유한 값을 저장하는 자료구조
- 값만 저장, 키 저장 x
- 값이 중복되지 않는 유일한 값으로 구성
- 기능 : 값 추가, 검색, 값 삭제, 모든 값 제거, 존재 여부 확인

 

Set - JavaScript | MDN

The Set object lets you store unique values of any type, whether primitive values or object references.

developer.mozilla.org

// 생성자 함수를 통한 생성
const mySet = new Set();

// 등록
mySet.add('value1');
mySet.add('value2');
mySet.add('value2'); // 중복값 발생시 무시
mySet.add('value5');
mySet.add('value7');
mySet.add('value9');

// 크기 확인
console.log(mySet.size); // 5

// 요소 확인
console.log(mySet.has('value1')); //true
console.log(mySet.has('value2')); //true
console.log(mySet.has('value3')); //false

// 반복 for ~ of ~
for (const value of mySet.values()){
    console.log(value);
}

3주차 1강 : 데이터타입의 종류 및 메모리

 

1. 데이터 타입


크게 기본형, 참조형으로 나뉘며, 데이터 타입을 나누는 기준은 값의 저장방식과 불변성 여부이다.

1-1. 기본형 
복제 방식 : 값이 담긴 주소값을 바로 복제 
불변성 : 불변하다.
종류 :
- Number
- String
- Boolean
- null
- undefined
- Symbol

1-2. 참조형

대체로 크기가 큰 데이터이다.
복제방식 : 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제
불변성 : 불변하지 않다
종류 : 
- Object
    - Array
    - Function
    - Date
    - RegExp
    - Map, WeakMap
    - Set, WeakSet 


2. 메모리와 데이터에 관한 배경지식


2-1. 비트 (bit)
- 컴퓨터가 이해할 수 있는 가장 작은 단위 (0,1)

2-2. 바이트 (byte)
- 8bit = 1byte

2-3. 메모리 (memory)
- 모든 데이터는 byte 단위의 식별자인 메모리 주소값을 통해 서로 구분이 된다.
* 자바스크립트의 정수는 8byte(64bit)의 크기를 가졌다. (다른 언어는 차이가 있음)

√ tip. 식별자 and 변수
변수는 데이터를 뜻하며, 식별자는 변수의 이름을 나타낸다
let num(식별자) = 3(변수)


3주차 2강 : 변수 선언과 데이터 할당(기본형 데이터)


메모리에 기본형 데이터가 저장되는 과정


기본가정 : 메모리는 변수를 저장하는 영역과 데이터를 저장하는 영역으로 나누어 활용한다.
1. 변수영역 메모리의 비어있는 공간에 선언한 식별자 저장
2. 데이터영역 메모리의 비어있는 공간에 식별자에 할당된 변수 값 저장
3. 식별자가 저장되있는 메모리 공간에서 변수값이 저장된 메모리의 주소를 참조


Q. 왜 데이터를 직접 저장하지 않고 참조된 주소를 저장하는가?


1. 자유로운 데이터 변환
정수는 8byte로 고정된 메모리 크기를 갖지만, 자바스크립트의 문자열은 고정된 값을 갖지않는다.
최초 할당된 문자열을 재할당하여 더 긴 문자열을 넣는 상황을 가정하였을 때, 
기존에 사용하던 메모리 공간보다 더 많은 공간을 필요로 하게된다.
이 때 데이터가 직접 메모리에 저장되어있다면, 뒤로 저장된 모든 데이터의 주소를 뒤로 밀어야하는 비효율적인 문제가 발생한다.
이에 반해, 참조된 주소값을 저장한다면, 참조 주소만 변경하면 된다.

2. 메모리를 효율적으로 관리
같은 값을 가진 100만개의 정수가 서로 다른 식별자에 할당되었다고 가정하자.
만약 변수영역 메모리에 데이터가 직접 저장이 된다면, 약 8byte(정수의 크기) * 100만의 메모리 공간을 사용하게된다.
이에 반해, 참조된 주소값을 저장한다면, 데이터 영역 메모리에 정수를 한번만 선언하고 그 참조주소 하나만 변수영역 메모리에서 참조하면 된다. 변수영역 메모리에서 사용하는 크기가 데이터 영역 메모리에서 사용하는 크기보다 작기 때문에 더 효율적인 메모리 관리가 가능하다. 


변수 VS 상수


변수 : 변수영역메모리(식별자와 참조주소가 저장된 메모리영역)를 변경할 수 있다. (데이터 참조주소 변경가능)
상수 : 변수영역메모리(식별자와 참조주수가 저장되 메모리영역)를 변경할 수 없다. (데이터 참조주소 변경 불가능)


불변하다 vs 불변하지 않다.


불변하다 : 데이터영역메모리(실제 값이 저장된 메모리)를 변경할 수 없다. (데이터를 변경하지 못함, 변하는 것이 아닌 새롭게 할당하는 개념, 이때 값이 변하면서 사용하지 않는 값은 JavaScript 가비지컬렉터에서 수거한다.)
불변하지 않다 :  데이터영역메모리(실제 값이 저장된 메모리)를 변경할 수 있다. (데이터를 변경할 수 있다, 최초 할당된 데이터의 참조주소를 계속 유지함)


3주차 3강 : 변수 선언과 데이터 할당(참조형 데이터) 변수 복사의 비교


메모리에 참조형 데이터가 저장되는 과정


기본가정 : 메모리는 변수를 저장하는 영역과 데이터를 저장하는 영역으로 나누어져 있으며, 추가로 가변형 데이터를 저장하는 영역을 가진다.
1. 변수영역 메모리의 비어있는 공간에 선언한 식별자 저장
2. 데이터영역 메모리의 비어있는 공간에 식별자에 할당된 변수 값 저장
3. 가변형 데이터에는 각 프로퍼티의 이름과 데이터 영역에 할당된 값을 참조하고 있는 주소를 할당한다.
4. 식별자가 저장되있는 메모리 공간에서는 가변형 데이터(프로퍼티)를 저장한 메모리 주소를 참조하고,
가변형 데이터를 저장한 메모리는 각각의 데이터 값을 저장한 데이터 영역 주소를 참조한다.

즉, 변수영역(식별자, 가변형데이터 메모리주소) > 가변형데이터를 저장한 메모리(프로퍼티와 그 값을 참조하는 주소) > 데이터 영역 메모리(데이터) 순으로 참조가 중첩되어 이루어진다.


따라서, 참조형 데이터는 데이터영역 메모리의 값이 변화하더라도 가변형데이터를 저장한 메모리 공간에서는 참조주소가 변화하기 때문에 불변하지 않다.

√ tip. 참조카운터
참조카운터가 0일 경우, 가비지 컬렉터에 수거

참조형 데이터 복사의 문제점

 

참조형 데이터를 변수 복사를 하면, 같은 주소를 공유하기 때문에 한쪽에서 변경이 이루어지면 다른 한쪽에서도 의도치 않은 변경이 일어난다.


3주차 4강 : 불변 객체 (얕은 복사 깊은 복사)

 

참조형 데이터를 변수 복사를 하면, 같은 주소를 공유하기 때문에 한쪽에서 변경이 이루어지면 다른 한쪽에서도 의도치 않은 변경이 일어난다.

따라서 참조형 데이터를 복사하는 방법이 정해져있으며, 각각의 방식을 얕은복사와 깊은복사라고 한다.

 

1. 얕은 복사

얕은 복사는 참조형 데이터 내에 참조형 데이터 한 뎁스가 존재할 때 사용하는 방법이다.

한 뎁스 이상 발생하게 되면 나머지 뎁스는 복사하지 못하는 문제가 있다.

// user 객체를 생성
var user = {
    name : 'Kim',
    gender : 'male',
};;

var copyObject = function (target) {
    var result={};
    // 객체를 property 하나하나를 추가하겠다. 단, 반복문을 통해서
    for (var prop in target) {
        result[prop] = target[prop];
    }

    return result;
}

var user2 = copyObject(user);
user2.name = "Lee";

if (user !== user2) { // 출력
    console.log('유저정보가 변경되었습니다.');
}

console.log(user.name, user2.name); // Kim Lee
console.log(user === user2); // false

 

2. 깊은 복사

얕은 복사의 문제점을 보완한 방식으로, 복사로직을 재귀처리하여, 모든 뎁스의 참조형 데이터를 복사한다.

// 깊은 복사는 기본적으로 프로퍼티를 모두 체크하되, 프로퍼티의 값이 Object 타입일경우 안쪽으로 파고들어 먼저 복사를 실시한다.

var copyObjectDeep = function(target) {
    var result = {}
    if (typeof target === 'object' && target !== null){
        // 프로퍼티를 다 훓어보겠다. 끝까지
        for (var prop in target) {
            result[prop] = copyObjectDeep(target[prop]);
        }
    }else {
        result = target;
    }
    return result;
}

var obj = {
    a : 1,
    b : {
        c : null,
        d : [1, 2],
    },
};

var obj2 = copyObjectDeep(obj);
obj2.a = 3;
obj2.b.c = 4;
obj2.b.d[1] = 3;

console.log(obj);
console.log(obj2);

3주차 5강 : null과 undefined

undefined : 자바스크립트 엔진에서 판단하기에 값이 없는 것
null : 개발자가 값이 없는 것을 명시적으로 표한한 것, 값이 없음을 표현할 때는 undefined보다 null을 사용자

var n = null;
console.log( typeof n ); // object > JavaScript버그

//동등연산자 (equality operator)
console.log(n == undefined); // true
console.log(n == null); //true

//일치연산자 (identify operator)
console.log(n === undefined); //false
console.log(n === null) //true

3주차 6강 : 실행 컨텍스트 및 콜 스택 소개


실행컨텍스트 


실행할 코드에 제공할 환경정보를 모아놓은 객체



실행 컨텍스트의 특징


1. 선언된 변수를 호이스팅
2. 외부 환경 정보 구성
3. this 바인딩

 

 

실행 컨텍스트의 구성 방법


1. 전역공간
2. eval() 함수
3. 함수 (주로 사용)

 


실행컨텍스트의 콜스택


코드를 실행할 때 필요한 환경 정보들을 모아 컨텍스트를 구성하며, 이 컨텍스트는 스택의 구조를 가진 '콜스택'에 저장한다. 이러한 방식으로 코드의 순서를 보장한다. 실행 컨텍스트는 스택에서 외부에 노출되어있는 컨텍스트가 실행된다.

// 1. 콜스택 누적 - 전역 컨텍스트
var a = 1; 

function outer() {
    function inner(){
        console.log(a);
        var a = 3;
    }
    // 3. 콜스택 누적 - inner 함수 컨텍스트, outer 함수 컨텍스트 , 전역 컨텍스트
    inner();
    // 4. 콜스택 누적 - outer 함수 컨텍스트 , 전역 컨텍스트
    console.log(a);
}
// 2. 콜스택 누적 - outer 함수 컨텍스트 , 전역 컨텍스트
outer();
// 5. 콜스택 누적 - 전역 컨텍스트 
console.log(a);
// 6. 콜스택 누적 -

3주차 7, 8강 record와 호이스팅


실행컨텍스트 객체 내부 프로퍼티


- VariableEnvironment (VE)
현재 컨택스트 내의 식별자 정보(record)를 가지고 있다.
외부환경정보(outer)
SnapShot 유지, 실시간으로 변경 x

- LexicalEnvironment (LE)
SnapShot 유지x, 실시간으로 변경사항 반영

* VE와 LE는 똑같다. (record, outer로 구성)
* 기능적 차이점은 변경사항(SnapShot)을 유지하는지 여부 차이다.
* 결국, 실행 컨텍스트를 생성할 때, VE에 정보(식별자)를 먼저 담은 다음, 이를 그대로 복사해서 LE를 만들고
이후 LE를 활용한다


1. enviromentRecord(=record)
: record는 현재 컨텍스트와 관련된 코드의 식별자 정보를 저장한다. 
코드를 처음부터 끝까지 순서대로 훑어가며 수집(실행 x)
* 호이스팅 : record가 식별자 정보를 런타임 이전에 저장하면서 발생
- 변수의 식별자, 함수 선언문은 호이스팅된다.
- 다만, 함수 표현식은 식별자에 함수의 정의를 하기 때문에 함수가 아닌 식별자가 호이스팅된다.
- 호이스팅의 문제가 있기 때문에 함수 선언문보다 함수 표현식을 쓰려고 노력해야한다.


2. outerEnvironmentReference(=outer)
: 현재 호출된 함수가 선언 될 당시 외부환경정보 즉 이전 컨텍스트정보를 가지고 있다.
현재 컨텍스트부터 스코프체인으로 연결된 외부 컨텍스트 정보를 검색하며 참조를한다.


-ThisBinding