[TIL] 230126 This, Closure
This
글로벌 컨텍스트의 This에는 두 가지 가 있다.
- 브라우저 에서의 This : Windws
- 노드 환경에서의 This: 모듈
노드 This
노드에서의 This
는 모듈을 뜻한다.
노드에서 consloe.log
에 this
를 찍으면 빈 객체가 나온다 { }
console.log(this);
이 모듈을 Exports 해주면 this
에는 export 된 { key: value }
가 들어간다.
const x = 0;
module.exports = x;
console.log(this)
그리고 globalThis
를 호출해서 확인하면, 노드에서 사용 가능한 전역 객체가 나온다,
console.log(globalThis);
전역 객체에 '점'을 붙이면 사용 가능한 전역 객체가 나오는데, 이 globalThis
를 생략하고 사용 가능하다.
브라우저 This
브라우저에서의 This
는 Window
를 뜻한다.
console.log(this); // window에 들어있는 다양한 window 객체 API
console.log(this.setTimeout); // window 안에 있는 setTimeout
console.log(setTimeout); // window에서 this 생략 가능
console.log(globalThis); // window에서 globalThis는 동일하게 window 객체가 나타남
함수 내부에서의 This
함수 내부에서 this
에 접근하면 globalThis
글로벌 객체에 접근하게 된다.
function someThis() {
console.log(this);
}
someThis();
var object1 = {
outer: function () {
console.log(this);
var innerFunc = function () {
console.log(this);
};
innerFunc(); // 2. window를 출력
var object2 = {
innerMethod: innerFunc,
};
object2.innerMethod(); // 3. object2를 출력
},
};
object1.outer(); // 1. object1을 출력
만약, 엄격 모드('use strict
') 에서는 Undefined
가 출력된다. 왜냐하면 함수란 스코프 내부에서 this
에 대한 디폴트 바인딩 정보가 없기 때문이다.
메서드 내부에서의 This
this
에는 호출한 주체에 대한 정보가 담기는데, 어떤 함수를 메서드로서 호출을 하게 되면 호출의 주체는 함수명(프로퍼티명) 앞의 객체이다.
var object = {
methodA: function () {
console.log(this);
},
inner: {
methodB: function () { console.log(this) }
}
};
object.methodA(); // object 출력
object.inner.methodB(); // object.inner 출력
콜백 호출 시 그 함수 내부에서의 This
콜백 함수 내에서 this
를 호출하게 되면 전역 객체를 가리키게 된다.
setTimeout(function () { // (1)
console.log(this);
}, 300);
[1, 2, 3, 4, 5].forEach(function (x) { // (2)
console.log(this, x);
});
document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a').addEventListener('click', function (e) { // (3)
console.log(this, e); // (4)
});
- 전역객체가 출력 ➜
- 전역 객체와 배열이 각 5회 출력 ➜
addEventListener
는 지정한HTML
엘리먼트에 'click
' 이벤트가 발생할 때마다, 그 이벤트 정보를 콜백 함수의 첫 번째 인자로 삼아 함수를 실행. ➜- 버튼을 클릭 시, 지정한 엘리먼트와 클릭 이벤트에 관한 정보가 담긴 객체가 출력
생성자 내부에서의 This
JS에서는 new
명령어와 함께 함수를 호출하게 되면 해당 함수가 생성자로서 동작하게 된다.
이때 내부에서의 this
는 곧 새로 만들 구체적인 인스턴스 자신이 된다.
var Cat = function (name, age) {
this.bark = '야옹';
this.name = name;
this.age = age;
};
var choco = new Cat('초코', 7);
var nabi = new Cat('나비', 5);
console.log(choco, nabi);
/*
Cat { bark: '야옹', name: '초코', age: 7 }
Cat { bark: '야옹', name: '나비', age: 5 }
*/
명시적 바인딩
개발자가 명시적으로 this
를 바인딩할 수 있는 방법은 call
, apply
, bind
메서드 등을 사용해, 명시적으로 this
를 지정하면서 함수 또는 메서드를 호출할 수 있다.
화살표 함수
화살표 함수는 특별한 this
바인딩을 가진다. 이 화살표 함수는 function
을 줄인 것처럼 보이지만, 여러 부분에서 일반 함수와 다른 점을 가지는데, this
와 관련된 점은 '화살표 함수에는this가 존재하지 않는다.'이다. 실행 콘텍스트 생성 시 this
를 바인딩하는 과정이 제외되었다.
접근하고자 하면 스코프체인상 가장 가까운 this에 접근하게 된다.
var object = {
outer: function () {
console.log(this);
var innerFunc = () => {
console.log(this);
};
innerFunc(); // { outer: [Function: outer] }
},
};
object.outer(); // { outer: [Function: outer] }
클로져
클로저는 특정한 두가지의 조합인데, 함수와 그 외부를 둘러싸고있는 렉시컬환경의 조합이다. 즉, 클로저란 내부 함수에서 외부 함수에 있는 상태에 접근할 수 있는 권한을 주고 있는 것이다.
function outer() {
const x = 0;
function inner() {
x
}
inner();
}
inner()
여기까지가 일반적인 실행 컨텍스트 스택
outer
함수에서 inner
함수를 선언하고 그 inner
함수를 return
했다. 즉, inner
라는 함수의 참조 값을 return
하게 되고, 전역 스코프에서 inner
라는 변수를 만들어 outer
함수를 할당했다. 이 inner
라는 변수는 outer
함수의 블록 스코프인 inner
함수를 가리키는 것
순서
앱실행 ➜ 전역 스코프 렉시컬 환경이 들어옴 ➜ outer 선언(렉시컬 환경 만들어짐) ➜ outer 호출 ➜ 실행 컨텍스트에 쌓임 ➜ inner 선언 (렉시컬 환경 만들어짐) ➜ inner을 반환(컨텍스트에 쌓이지 않음) ➜ outer 스코프가 끝나면 실행 컨텍스트 스택에서는 빠지지만, inner 렉시컬 환경에서는 return 되었기 때문에 스코프 체인에는 그대로 남아있다.