TIL : this

hihyeon_cho·2023년 2월 3일
0

TIL

목록 보기
63/101
post-thumbnail

this ?

: 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기참조변수.

this를 쓰는 이유

const circle = {
	radius : 5,
	getDiameter(){
		return 2 * circle.radius;
	}
};

console.log(circle.getDiameter()); // 10

객체리터럴(↑) 방식으로 작성한 위의 코드를 아래와 같이 생성자 함수(↓)방식으로 작성했을 때,

function Circle(radius){
	 ????.radius = radius;
}

Circle.prototype.getDiameter = function(){
		return 2 * ????.radius;
};

const circle = new Circle(5);

생성자 함수를 정의하는 시점이 인스턴스 생성하기 이전이기 때문에 우리는 .radius가 참조해야하는 식별자를 확인할 수 없다. ( ???? 부분에 넣을 부분 )
그래서 this 바인딩이 필요하다.


this 바인딩?

: this + 바인딩(식별자와 값을 연결)
⇒ 함수를 호출함으로서 this가 가리키는 객체를 결정( 연결 )하는 것.

같은 함수라도 각각 실행되는 환경이 다르다.

  • 변수에 저장되는 함수
  • 함수의 인수로 전달되는 함수
  • 반환값으로 사용되는 함수
  • 단독으로 호출되는 함수
  • 객체 내 메서드로 호출되는 함수
    👉🏻 각각의 함수가 가리키는 this가 다르다.

⭐ 어떤 실행환경에서, 어떤 객체에 의해 호출되는 지에 따라 this가 달라진다.
⇒ 함수가 호출되는 방식에 따라 this 바인딩이 동적으로 결정된다.



함수 호출방식에 따른 this바인딩

일반 함수 호출

  • 기본적으로 this에는 전역객체가 바인딩 된다.
  • 일반 함수로 호출된 모든 함수( + 중첩함수, 콜백함수 포함 ) 내부의 this에는 전역객체 window가 바인딩 된다.
// 전역
console.log(this) // window

// 일반함수 ==> 전역 객체 window를 가리킨다. 
function square(number){
	console.log(this); // window
	return number * number;
}

square(2);
function foo(){
	'use strict'; // => this에 ~~window가 아닌~~ undefined가 바인딩 된다. 

	console.log("foo's this : ", this); // undefined
}
foo();
  • 중첩함수와 콜백함수
var value = 1;

const obj = {
	value : 100,
	foo(){
		console.log(this); // { value : 100, foo : 𝑓 }
		console.log(this.value); // 100
		function bar(){
			console.log(this); // window
			console.log(this.value); // 1
		}
		bar();
	}
};
d
obj.foo();
var value = 1;

const obj = {
	value : 100,
	foo(){
		console.log(this); // { value : 100, foo : 𝑓 }
		console.log(this.value); // 100
		setTimeout( function bar(){
			console.log(this); // window
			console.log(this.value); // 1
		},100);
	}
};

obj.foo();

어떠한 함수라도 일반함수로 호출되면 this에 전역객체가 바인딩 된다.

중첩함수 or 콜백함수 = 외부 함수를 돕는 헬퍼 함수

외부함수의 메서드의 this ≠ 중첩함수 혹은 콜백함수의 this

헬퍼함수로 동작하기 어려워짐

this를 일치시키기 위한 방법

1. this 바인딩을 변수에 할당하기

    ```jsx
    var value = 1;
    
    const obj = {
    	value : 100,
    	foo(){
    		console.log(this); // { value : 100, foo : 𝑓 }
    		const that = this; 
    		setTimeout( function bar(){
    			console.log(that.value); // 100
    		},100);
    	}
    };
    
    obj.foo();
    ```
    

2. Function.prototype.apply / call / bind 메서드 사용하기

    = 콜백함수에 명시적으로 this를 바인딩하는 방법
    
    ```jsx
    var value = 1;
    
    const obj = {
    	value : 100,
    	foo(){
    		setTimeout( function bar(){
    			console.log(this.value); // 100
    		}.bind(this),100);
    	}
    };
    
    obj.foo();
    ```
    

3. 화살표함수 사용하기

    ```jsx
    var value = 1;
    
    const obj = {
    	value : 100,
    	foo(){
    		setTimeout(()=> console.log(this.value),100); // 100
    	}
    };
    
    obj.foo();
    ```
    

메서드 호출

: 메서드 내부의 this에는 메서드를 호출한 객체, 마침표 연산자 앞에 기술한 객체가 바인딩된다. 메서드를 소유한 객체가 아닌 메서드를 호출한 객체 에 바인딩 된다는 점을 주의 !

const person = {
	name <: 'Lee',
	getName(){
		return this.name;
	}
};

console.log(person.getName()); // 'Lee'

getName 프로퍼티가 가리키는 함수 객체는 person 객체에 포함된 것이 아니라 별도의 객체로 getName프로퍼티가 함수를 그저 가리키고 있을 뿐이다.

const anotherPerson = {
	name : 'Kim'
};

//다른 객체의 프로퍼티에 할당
anotherPerson.getName = person.getName;

//다른 객체의 메서드가 될 수 있으며
console.log(anotherPerson.getName()); //Kim

// 변수에 할당되어 일반함수로 호출될 수도 있다. 
const getName = person.getName;
console.log(getName()); // '' 

프로토 타입 메서드 내부에서 사용된 this도 메서드를 호출한 객체에 바인딩 된다.

function Person(name){
	this.name = name;
}

Person.prototype.getName = function(){
	return this.name
};

const me = new Person('Lee');
console.log(me.getName()); // Lee

Person.prototype.name = 'Kim';
console.log(Person.prototype.getName()); // Kim

생성자 함수 호출

  • 생성자 함수 내부의 this에는 생성자 함수가 ( 미래에 ) 생성할 인스턴스가 바인딩된다.
    function Circle(radius){
    	this.radius = radius;
    	this.getDiameter = function(){
    		return 2 * this.radius;
    	};
    }
    
    const circle1 = new Circle(5);
    const circle2 = new Circle(10);
    
    console.log(circle1.getDiameter()); // 10
    console.log(circle2.getDiameter()); // 20
  • new연산자와 함께 호출하지 않으면 생성자 함수로 동작하지 않으므로, 일반적인 함수의 호출이 된다.

Function.prototype.apply/call/bind 메서드에 의한 간접 호출

  • this로 사용할 객체와 인수 리스트를 인수로 전달받아 함수를 호출한다.
  • Function.prototype.apply / Function.prototype.call : 함수를 호출하는 기능을 한다. 첫번째 인수로 전달한 특정객체를 호출한 함수의 this에 바인딩한다.
    Function.prototype.apply(thisArg[,argsArray])
    
    // thisArg = this로 사용할 객체
    // argsArray = 함수에게 전달할 인수 리스트의 **배열** or **유사배열객체**
    Function.prototype.call(thisArg[,arg1[,arg2[,...]]])
    
    // thisArg = this로 사용할 객체
    // arg1,arg2, ... = 함수에게 전달할 인수 **리스트**
    ⇒ 인수를 전달하는 방식만 다를 뿐 동일하게 동작한다.
  • Function.prototype.bind
    • apply와 call과 달리 함수를 호출하지 않는다.
    • 첫번째 인수로 this 바인딩이 교체된 함수를 새롭게 생성해 반환한다.
    • 메서드의 this와 메서드 내부의 중첩함수 or 콜백함수의 this가 불일치하는 문제를 해결하기 위해 사용된다.
      const person = {
      	name : 'Lee',
      	foo(callback){
      		setTimeout(callback,100);
      	}
      };
      
      person.foo(function(){
      	console.log(`Hi! I'm ${this.name}.`); // Hi! I'm .
      }); 
      
      // 콜백함수가 일반함수라 this가 window
      const person = {
      	name : 'Lee',
      	foo(callback){
      		setTimeout(callback.bind(this),100);
      		// bind메서드로 callback함수의 내부의 명시적으로 this바인딩.
      	}
      };
      
      person.foo(function(){
      	console.log(`Hi! I'm ${this.name}.`); // Hi! I'm Lee.
      });

함수 호출방식에 따른 this 바인딩

일반 함수 호출 ⇒ 전역객체

메서드 호출 ⇒ 메서드를 호출한 객체

생성자 함수 호출 ⇒ 생성자 함수가 생성할 인스턴스

Function.prototype.apply/call/bind
메서드에 의한 간접 호출
⇒ Function.prototype.apply/call/bind 메서드에 첫번째 인수로 전달한 객체

profile
코딩은 짜릿해 늘 새로워 ✨

0개의 댓글