I. 렉시컬(정적) 스코프 lexical(static) scope : 함수가 정의된 위치에 따라 변수의 유효 범위가 결정되는 스코프 규칙이다. 이것은 코드가 작성된 위치에 기반하여 스코프가 정적으로 결정되는 것을 의미한다.
--> 렉시컬 스코프의 핵심 아이디어는 함수가 어디에서 호출되는지가 아니라 어디에서 정의되는지에 따라 변수에 대한 접근 권한이 결정된다는 것이다.

여기서 inner 함수는 outer 함수 내에서 정의되었다. 따라서 inner 함수는 outer 함수의 스코프에 접근할 수 있다. 함수 inner가 호출될 때, outerVar 변수에 접근하여 그 값을 출력할 수 있다.

II. 렉시컬 환경 lexical environment

위의 그림과 같이 func2()에서 없을 경우, func1()를 찾아보고, func1()에도 없을 경우, 전역 렉시컬 환경에서도 찾아보면서 타고타고 내려가게 된다.
III. 클로저 closure
내부 함수 --> 외부 함수의 값에 접근할 수 있다는 개념(함수 중첩시)

func1 함수 내부에 정의된 func2 함수는 외부 함수인 func1의 변수인 word를 참조하고 있다. 이때 func2 함수가 func1 함수 외부에서 호출되더라도 word 변수에 접근할 수 있다.

createCounter 함수는 외부에서 시작값(start)을 받아와서 내부에서 정의된 함수를 반환한다. 반환된 함수는 시작값을 기준으로 숫자를 증가시키고 그 값을 출력하는 역할을 한다.
createCounter 함수가 호출될 때 시작값 start가 전달된다. 이 시작값은 클로저 내부에서 유지될 변수이다.
createCounter 함수 내부에서는 익명 함수가 정의되고 반환된다. 이 익명 함수는 외부에서 count 변수에 할당된다.
반환된 함수가 count 변수에 할당되면서, 이 함수는 클로저를 형성하게 된다.
--> 클로저는 createCounter 함수가 종료된 이후에도 외부 변수인 start에 접근할 수 있다.
--> count 함수가 호출될 때마다 시작값 start가 증가하고, 그 값을 출력한다.
I. ⭐️ this - "이곳의~"
1 . 전역에서의 this

2 . 함수 안에서의 this


3 . 객체 안에서의 this
a. 객체 리터럴 - 해당 객체를 가리킴
this.x는 메서드가 호출된 객체를 가리킨다. 따라서 obj.getX()를 호출하면 this는 obj 객체를 참조하게 되고, 따라서 x 속성인 123의 값을 반환한다.b. 생성자 함수 - 생성될 인스턴스를 가리킴

Person 함수는 이름(name)과 나이(age)를 매개변수로 받아 객체를 생성한다. this를 사용하여 name과 age 속성을 설정하고, introduce 메서드를 정의한다.
이후에는 new Person('이서연', 20).introduce()를 호출하여 Person 생성자 함수를 사용하여 객체를 생성하고, 해당 객체의 introduce 메서드를 호출하여 객체를 소개하는 문자열을 반환한다.
c . 클래스 선언 - 생성될 인스턴스를 가리킴

II. ⭐ 동적 바인딩
이와 같이 korean, italian을 명시해두고, korean을 출력해보자

makeStew이름의 함수를 살펴보면, isHot이 true일 경우, 매운, false일 경우, 순한을 출력하는 코드이다. 이후, korean.makeStew(true,2)를 출력하니, 매운김치찌개, 2냄비가 출력된 것을 확인할 수 있다.
찌개를 만드는 기술을 이탈리안 친구에게 전달하기 위해서
italian.makeStew = korean.makeStew 로 전달해보았다. 이후, italian을 출력해보니

김치찌개가 아닌, 피자찌개가 출력된 것을 확인할 수 있다.
const italian = {
favorite : '피자'
makeStew : function(isHot, pots) {
return `${isHot? '매운' : '순한'}${this.favorite}찌개, ${pots}냄비`;
}
};
여기서 this.favorite는 italian의 favvorite인 피자를 가리키고 있기 때문이다.
여기서, 김치찌개를 출력하고 싶을 때는 어떻게 해야할까?
--> call, apply bind 를 사용하면 된다!
call, apply, bind는 모두 함수를 호출할 때 this 값을 명시적으로 지정할 수 있는 메서드이다.
이들은 주로 함수의 컨텍스트를 변경하거나 다른 객체의 메서드를 호출할 때 사용된다.
1 . call를 사용한 함수 호출
call: 함수를 호출하면서 첫 번째 매개변수로 지정한 객체를 함수 내부에서 this로 사용한다.
그리고 추가적인 매개변수를 전달하여 함수를 호출할 수 있다.

2 . apply를 사용한 함수 호출
call과 유사하지만, 함수에 전달할 인수를 배열로 받는다. 이 배열의 각 요소가 함수 내부의 매개변수에 순서대로 매핑된다.

3. ⭐ bind를 사용한 this 대상 고정
함수를 호출하지는 않지만, 함수의 this 값을 영구적으로 바인한다.
원본 함수의 복사본을 만들어 반환하며, 이 복사본은 바인딩된 this 값을 가지게 된다. 추가 인수가 전달되면 해당 인수들이 원본 함수의 매개변수에 바인딩됩니다.


4 . 바인딩된 함수를 내보내는 함수

5 . 생성자 함수일 경우 - 함수 자체를 미리 인스턴스에 바인딩하기

6 . call, apply, bind의 다른 활용
어느날 된장찌개가 먹고 싶다면?

call 메서드를 사용하면 함수를 호출할 때 this 값을 지정할 수 있다. 첫 번째 매개변수로 지정한 객체가 함수 내부에서 this로 사용되며, 이후에는 함수의 매개변수를 순서대로 전달하여 호출할 수 있다.
따라서 위 코드의 출력은 korean 객체의 makeStew 메서드를 호출하되, this를 {favorite: '된장'} 객체로 설정하여 호출한 결과를 나타낸다. 이는 된장을 사용하여 매운 또는 순한 찌개를 만들고, 2냄비를 사용하는 결과를 반환한다.

intro 함수는 this를 이용하여 객체의 name과 age 속성을 참조하고, job 매개변수를 이용하여 해당 객체의 직업을 설명하는 문자열을 반환한다.
lee 객체는 name과 age 속성을 가지고 있으며, intro 함수를 lee 객체의 메서드로 추가한 후 호출하고 있다.
이렇게 하면 lee 객체의 intro 메서드를 호출할 때 this는 lee 객체를 가리키게 되어 name과 age 속성을 참조할 수 있다.

위 코드는 intro 함수를 호출하되, this를 명시적으로 lee 객체로 설정하여 호출한다. 또한, call과 apply 메서드를 사용하여 함수를 호출할 때 this 값을 지정하고, 추가적인 인자를 전달한다.
call: 함수를 호출할 때 첫 번째 매개변수로 지정한 객체가 함수 내부에서 this로 사용된다.
apply: call과 유사하지만, 추가적인 인자를 배열로 받아 함수의 매개변수에 전달한다.
따라서 위 코드에서는 intro 함수를 호출할 때 this를 lee 객체로 설정하여 호출하고 있다. 또한, call과 apply 메서드를 사용하여 job 매개변수를 전달하고 있다.
⭐ 배열 메서드의 thisArg

const car = {
brand: 'Toyota',
model: 'Corolla',
getInfo: function () {
return `${this.brand} ${this.model}`;
}
};
const cars = [
{ brand: 'Ford', model: 'Focus' },
{ brand: 'Honda', model: 'Civic' },
{ brand: 'Chevrolet', model: 'Malibu' }
];
cars.forEach(function (carInfo) {
console.log(this.getInfo.call(carInfo)); // 각 객체의 정보를 호출하여 출력
}, car);
다른 예시를 살펴보자


: 정적 바인딩(static binding)은 실행 컨텍스트에서 this 키워드가 함수가 호출될 때가 아니라, 함수가 정의될 때 바인딩되는 것을 의미
일반적으로 자바스크립트에서 함수를 호출할 때 this의 값은 호출 방법에 따라 동적으로 결정된다. 하지만 화살표 함수의 경우 this는 정적으로 바인딩되어 함수가 정의될 때 외부의 컨텍스트에 의해 결정된다. 이것이 정적 바인딩이다.
객체의 메서드 종류별 비교
const obj = {
// function 선언 함수
func1: function () { return true; },
// 메서드
func2 () { return true; },
// 화살표 함수
func3: () => true
}
console.log(
obj.func1(),
obj.func2(),
obj.func3()
);
=> 기호를 사용하여 정의
⭐ 화살표 함수와 this





Korean 클래스의 makeStew 메서드는 일반적인 메서드 정의 방식으로 정의되었으며, 이 메서드가 호출될 때의 this는 해당 메서드를 호출한 객체인 korean을 가리킨다. 따라서 italian.makeStew(false)를 호출할 때 makeStew 메서드 내에서의 this는 korean 객체를 가리키므로, 피자찌개가 출력된다.
반면에 fryRice 메서드는 화살표 함수로 정의되었으며, 화살표 함수는 정의된 시점의 외부 스코프의 this 값을 가져와서 사용하므로, fryRice 메서드 내에서의 this는 Italian 클래스를 생성한 객체인 korean을 가리키게 된다. 따라서 italian.fryRice(false)를 호출할 때 fryRice 메서드 내에서의 this는 korean 객체를 가리키므로, 김치볶음밥이 출력된다.
💡 call, apply, bind의 this 인자 무시됨
--> 화살표 함수를 사용하면 위와 같은 call, apply, bind의 사용이 무시된다.

1 . 클로저를 활용해서, 함수 생성시 인자로 주어진 수를 함수 실행시 인자로 주어진 수와 곱한 결과를 반환하는 코드를 작성해보자.

2 . width 와 height 프로퍼티를 갖고 있는 객체들이 각자의 넓이를 출력할 때 사용할 수 있는 외부 함수를 만들고, 이를 사용하는 코드를 작성해보자


3 . 어떤 값이 출력되는지 맞춰보자!
class Obj1 {
constructor (name) {
this.name = name;
this.arrowFunc = () => this.name;
}
normFunc () { return this.name }
}
class Obj2 {
constructor (name) {
this.name = name;
}
}
const obj1 = new Obj1('Apple');
const obj2 = new Obj2('Banana');
obj2.arrowFunc = obj1.arrowFunc;
obj2.normFunc = obj1.normFunc;
console.log(
obj2.arrowFunc(),
obj2.normFunc()
);
정답 : Apple, Banana
obj2.arrowFunc = obj1.arrowFunc;
obj2.normFunc = obj1.normFunc;