# this 자바스크립트는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다. ## this의 동작 방식 4가지 ### 1. 함수 호출 ```javascript= var a = 20; console.log(a); function func(){ var b = 10; console.log(this.a); // 20 console.log(this.b); // undefined function innerFunc(){ console.log(this.a); // 20 } innerFunc(); } ``` 기본적으로 함수에서 this는 전역객체(브라우저: window, 노드: global)에 바인딩된다. 내부함수는 일반 함수, 메소드, 콜백함수 어디에서 선언되었든 관게없이 this는 전역객체를 바인딩한다. ### 2. 메서드 호출 ```javascript= var first = red; function say() { console.log(`my first color is ${this.first}`); } const color = { first:blue, } color.say = say; color.say(); // my first color is blue; say(); // my first color is red; var func = color.say; func(); // my first color is red; ``` 함수가 객체의 프로퍼티 값이면 메소드로서 호출된다. 이때 메소드 내부의 this는 해당 메소드를 소유한 객체, 즉 해당 메소드를 호출한 객체에 바인딩된다. ### 3. 생성자 함수 호출 ```javascript= var first = red; function Color(color){ this.first = color; function say() { console.log(`my first color is ${this.first}`); } } const myColor = new Color("blue"); myColor.say(); // my first color is blue; Color.say(); // my first color is red; ``` 자바스크립트는 기존 함수에 new 연산자를 붙여서 호출하면 생성자 함수로 동작한다. 일반적으로 생성자 함수명은 첫문자를 대문자로 작성한다. 일반 함수를 호출하면 this는 전역객체에 바인딩되지만 new 연산자와 함께 생성자 함수를 호출하면 this는 생성자 함수가 암묵적으로 생성한 빈 객체에 바인딩된다. #### 생성자 함수 동작 방식 1. new 호출 시 새 객체가 만들어짐 2. 새로 생성된 객체의 Prototype 체인이 호출 함수의 프로토타입과 연결됨 3. 1에서 생성된 객체에 this를 바인딩하여 함수 코드가 실행됨 4. new의 반환값으로 return문이 없는 한 1에서 생성된 객체가 반환됨 ### 4. apply, call, bind 함수 호출 ```javascript= const 철수 = { first: red, }; const 영희 = { first: green, }; const 미애 = { first:blue, }; function color(name) { console.log(`my name is ${name} and my first color is ${this.first}`); } color.call(철수, "철수"); // my name is 철수 and my first color is red color.apply(영희, ["영희"]);// my name is 영희 and my first color is green color.bind(미애)("미애"); // my name is 미애 and my first color is blue ``` this를 특정 객체에 명시적으로 바인딩하는 방법은 apply, call, bind 메소드를 이용하면 된다. 이 메소드들은 모든 함수 객체의 프로토타입 객체인 Function.prototype 객체의 메소드이다. apply나 call 메소드는 this를 특정 객체에 바인딩할 뿐 본질적인 기능은 함수 호출이다. bind 메소드는 기존 함수 this를 특정 객체에 바인딩한 새로운 함수를 리턴한다. ## 화살표 함수에서의 this 화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다. 화살표 함수의 this는 언제나 상위 스코프의 this를 가리킨다. 화살표 함수는 call, apply, bind 메소드를 사용하여 this를 변경할 수 없다. ```javascript= var obj ={ rainbow:{ "빨강":0, "주황":1, "노랑":2, "초록":3, "파랑":4, "남색":5, "보라":6, }, } function getRainbow(colorArray) { return colorArray.filter((color) => { return color in this.rainbow; }) } obj.f1 = getRainbow; obj.f1(["레드","빨강","하늘","파랑"]) // 빨강 파랑 const getRainbow = (colorArray) => { return colorArray.filter((color) => { return color in this.rainbow }) } obj.f2 = getRainbow; obj.f2(["레드","빨강","하늘","파랑"]) // undefined error const getRainbow = (colorArray) => { return colorArray.filter(function(color){ return color in this.rainbow }) } obj.f3 = getRainbow; obj.f3(["레드","빨강","하늘","파랑"]) // undefined error function getRainbow(colorArray){ return colorArray.filter(function(color){ return color in this.rainbow }) } obj.f4 = getRainbow; obj.f4(["레드","빨강","하늘","파랑"]) // undefined error ``` arrow는 선언되는 당시에 정적으로 this binding 일반 함수는 호출되는 시점에 this binding 일반 함수의 내부 callback으로 arrow가 오는 경우에는 arrow의 this가 결정되는 시점이 상위 함수가 호출되는 시점에 binding 됨 설명을 쉽게하기 위해서 getRainbow = 상위 함수, filter의 callback 함수 = 하위 함수 로 지칭함 f1의 경우 상위 함수는 일반 함수, 하위 함수는 arrow 함수이므로 하위 함수에서 this가 결정되는 시점은 상위 함수가 호출되는 시점이다. 위코드에서는 **14번째**라인에서 this가 결정된다. 이때 상위 함수의 this는 obj이므로 arrow 함수인 하위 함수는 상위 스코프의 this를 참조하기때문에 하위함수의 this 역시 obj로 설정된다. f2의 경우 상위 함수는 arrow 함수, 하위 함수도 arrow 함수이다. 상위 함수가 arrow 함수이므로 선언될때 this가 결정되므로 상위 함수의 this는 **global**로 설정된다. 상위 scope가 **global**이고, arrow 함수는 상위 스코프를 따라가므로 하위 함수의 this도 **global**이 된다. f3,f4의 경우 하위 함수가 일반 함수인 경우이다. 내부 함수의 경우 this는 **global**로 설정된다.