-
[JavaScript] This, ClosureJavaScript 2024. 1. 21. 08:00728x90반응형
this, closure
this
this란?
자바스크립트에서의 this는 함수 호출 방식에 따라서 결정됨
함수의 호출방식
- 메소드로서의 호출
메소드로 호출 시(ex: obj1.addNums) 자신을 호출한 대상이 this
- 함수로서의 호출
함수를 독립적으로 호출 시 호출주체를 알 수 없으므로 this 지정 x -> 때문에 this는 전역 객체를 가리킴
또한 메소드의 내부라고 해도 함수로서 호출하면 this는 전역객체를 의미함- 콜백함수로 호출될 때 그 함수 내부에서의 this
콜백함수도 함수이기 때문에 this는 전역객체를 참조하지만, 콜백함수를 넘겨받은 함수에서 별도로 this를 지정한 경우 예외적으로 그 대상을 참조함
- 생성자 함수 호출
this는 인스턴스를 가리킴
- apply, call, bind 호출
apply, call, bind는 원하는 this를 바인딩할 수 있는 메소드임
- apply
var func = function (a, b, c) { console.log(this, a, b, c); }; func.apply({ x: 1 }, [4, 5, 6]); // { x: 1 } 4 5 6 var obj = { a: 1, method: function (x, y) { console.log(this.a, x, y); } }; obj.method.apply({ a: 4 }, [5, 6]); // 4 5 6- call
var func = function(a,b,c) { console.log(this, a,b,c,) } func(1,2,3) // window{…} 1 2 3 func.call({x: 1}, 2,3,4) // {x:1} 2 3 4- bind
call이나 apply랑 비슷해보이지만 call과 다르게 즉시 호출하지 않고 넘겨받은 this 및 인수들을 바탕으로 새로운 함수를 리턴하는 메소드
var func = function (a,b,c,d) { console.log(this, a,b,c,d) } func(1,2,3,4) // this는 window 객체 가리킴 var bindFunc = func.bind({x:1}) bindFunc(5,6,7,8) // {x:1}, 5, 6, 7, 8 // 부분 적용함수 var bindFunc2 = func.bind({x:1, 4, 5}) bindFunc2(6,7) // {x:1}, 4, 5, 6, 7Closure
Closure란?
외부함수의 생명주기가 이미 종료되었음에도 내부함수가 외부 함수의 컨텍스트에 접근할 수 있는 것을 말함 → 이미 종료된 외부함수의 변수 등을 여전의 참조(외부함수의 렉시컬 환경을 여전히 참조)할 수 있음
어떻게 접근할 수 있냐면 가비지 컬렉터가 보고 외부함수의 렉시컬환경을 아직 참조하는 곳이 있어 냅두기 때문임
예시
const x = 1; function outer() { const x = 10; const inner = function () { console.log(x); // 10 }; return inner; } const innerFunc = outer(); innerFunc();const innerFunc = outer() <- 이 부분에서 outer 함수를 호출하고 그 결과인 inner 함수를 innerFunc에 할당함
outer 함수는 inner 함수를 반환한 후 콜스택에서 사라짐. 하지만 outer 함수의 렉시컬 환경은 inner 함수가 여전히 참조하고 있으므로 사라지지 않음
innerFunc() <- inner 함수를 호출하면 이 함수는 자신이 선언됐던 렉시컬 환경인 outer 함수의 환경을 참조하여, outer 함수 내부에 선언된 x 변수를 사용할 수 있음. 이렇게 함수가 자신이 선언된 환경을 기억하는 특성이 바로 클로저임
inner 함수는 console.log(x)를 실행한 후 콜스택에서 사라짐
따라서 함수가 생성될 때 렉시컬 환경을 기억하고, 이후에도 그 환경에 접근할 수 있는 이런 특성이 클로저임. 이를 통해 함수 외부에서 접근할 수 없는 private한 변수를 만들 수 있음그러면 클로저는 왜 사용하는 걸까?
- 상태유지
현재 상태를 기억하고 변경된 최신 상태를 유지하는 것
예시
function makeCounter() { let count = 0; return function() { return count++; } } let counter1 = makeCounter(); console.log(counter1()); // 0 console.log(counter1()); // 1- 전역 변수 사용 억제
자신이 생성되었을 때의 lexical 환경을 기억하기 때문
예시
let count = 0; function makeCounter() { return function () { return ++count; }; } let counter1 = makeCounter(); console.log(counter1(), "before"); // 0 count = 1000; console.log(counter1(), "after"); // 1001- 정보의 은닉
예시
// 생성자 함수 function Person(name, age) { this.name = name; //public let _age = age; //private this.sayHi = function () { console.log(`Hi! My name is ${this.name}. I am ${_age}.`); }; } const me = new Person("Choi", 33); me.sayHi(); // Hi!, My name is Choi. I am 33. console.log(me.name); // Choi console.log(me._age); // undefined const you = new Person("Lee", 30); you.sayHi(); // Hi! My name is Lee. I am 30. console.log(you.name); // Lee console.log(you.age); // undefined위 코드에서 me._age나 you.age에 접근하면 undefined가 나오는 이유
_age는 Person 함수의 내부에서만 사용하는 변수라서 외부에서 접근할 수 없음
변수 _age는 Person 함수 내부에서만 접근가능하고(은닉화), 함수가 종료되면 콜스택에서 사라지지만 클로저로 인해 메소드 SayHi 함수에서 계속 접근이 가능함me.name이 되는 이유는 Person 객체의 인스턴스의 name 속성을 나타내고, 이 속성은 어디서든 접근가능하고 변경할 수 있는 public 속성이기 때문임. 따라서 me.name이나 you.name이라고 하면 그 속성값이 나옴
반응형'JavaScript' 카테고리의 다른 글
[JavaSript] 버블링, 캡쳐링, 이벤트위임 (0) 2024.01.30 [JavaScript] 얕은 복사, 깊은 복사 (0) 2024.01.28 [JavaScript] 콜백함수, 비동기 (0) 2024.01.27 [JavaScript] 실행 컨텍스트 (0) 2024.01.17 [Javascript] variables, hoisting (0) 2024.01.15