this 에 대해서

·2022년 4월 28일
0

javascript을 보자

목록 보기
1/2

this

This는 자기자신 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수이다

바인딩이란 식별자와 값을 연결하는것,
그럼 this 바인딩은 this 라는 식별자 와 this가 가리킬 객체를 연결하는것이다
다르게 말하면 this라는 변수명에 this가 가르킬 메모리 값을 연결시킨다고 생각하면된다

this바인딩은 함수 호출 방식에 의해 동적으로 결정된다.

tc39 에서의 정의

13.2.1.1 Runtime Semantics: Evaluation

PrimaryExpression : this

  1. 1. Return ? ResolveThisBinding().

9.4.4 ResolveThisBinding ( )

The abstract operation ResolveThisBinding takes no arguments and returns either a normal completion containing an ECMAScript language value or a throw completion. It determines the binding of the keyword this using the LexicalEnvironment of the running execution context. It performs the following steps when called:

1. Let envRec be GetThisEnvironment().

GetThisEnvironment ( )

The abstract operation GetThisEnvironment takes no arguments and returns an Environment Record. It finds the Environment Record that currently supplies the binding of the keyword this. It performs the following steps when called:

  1. 1. Let env be the running execution context's LexicalEnvironment.
  2. 2. Repeat,
    a. Let exists be env.HasThisBinding().
    b. If exists is true, return env.
    c. Let outer be env.[ [OuterEnv]].
    d. Assert: outer is not null.
    e. Set env to outer.

2. Return ? envRec.GetThisBinding().

GetThisBinding(): Return the value of this Environment Record's this binding. Throws a ReferenceError if the this binding has not been initialized.

this 바인딩은 처음
추상 작업 ResolveThisBinding() -> GetThisEnvironment() 통해서 실행컨택스트의 LexicalEnvironment 를 찾고 가장 가까운 HasThisBinding() 찾기위해서 계속해서
[ [OuterEnv]] 로 상위 환경 레코드를 탐색한다

HasThisBinding과 GetThisBinding 에 대해서는 각 환경레코드에 따라서 설명이 조금씩 달라진다, 자세한건 실행 컨텍스트에서..
Declarative Environment Records
Obejct Environment Records HasBinding
Function Environment Records
Global Environment Records
Module Environment Records

일반 함수 호출

this가 전역객체에 바인딩된다

strict모드 일시에 undefined가 바인딩 된다.

매서드내에 정의한 중첩함수도 일반 함수로 호출되면 this는 전역으로 바인딩 된다.

let a={   
    test(){
        console.log(this) // a
        function test2(){
        	console.log(this) // globalThis           
        }

        test2()
    }
}

위 코드와 같이 일반 함수처러 호출된다면 (콜백 중첩함수등) 내부 this는 전역 객체에 바인딩 되기때문에

객체 내부에서
const that=this 으로 변수에 받아서 이후 함수에서 that을 참조해서 바인딩을 하거나
bind apply calla 메서드를 사용해보자

메서드 호출

메서드 내부에서 this는 메서드를 호출한 객체, (.) 앞의 기술한 객체에 바인딩 된다.
중요한것은 메서드를 호출한 객체에 바인딩 된다.

const 사람={
	이름: "김",
	너의이름은(){
		return this.이름
	}
}
const 다른사람={
	이름: "박"
}

다른사람.너의이름은=사람.너의이름은

너의이름은=사람.너의이름은

console.log(사람.너의이름은()) // 김
console.log(다른사람.너의이름은()) // 박
console.log(너의이름은()) // this가 글로벌로 바인딩

생성자 함수 호출

생성자 함수 내부의 this는 생성자 함수가 미래에 생성할 인스턴스에 바인딩 된다
하지만 new를 쓰지않을 경우 일반함수 호출처럼 동작된다.

Function.prototype.apply

Function.prototype.call

Function.prototype.bind

3개의 함수는 Function.prototype의 메서드이다.

apply와 call은 this로 사용할 객체와 인수리스틀 받아서 함수를 호출한다.

call

func.call(thisArg[, arg1[, arg2[, ...]]])

형태로 호출을 할 수 있다.
thisArg는 func에 넘길 인자값을 넘기면 된다. call은 인수 목록 을 넘긴다

function 디스바인드(인자들){
	console.log(this)	
	console.log(arguments)	
}

const 인자={
	테스트:"테스트"		
} 

console.log(디스바인드.call(인자,1,2,3)) 
console.log(디스바인드.apply(인자,[1,2,3])) 
//{테스트:"테스트"}, Arguments [1,2,3]...

만약 call에다가 apply처럼 배열로 넘기면

console.log(디스바인드.call(인자,[1,2,3])) 
//{테스트:"테스트"}, Arguments [Array(3)]...

와 같이 인자들로 인식 하는것이 아닌 하나의 배열로 인자를 받아버린다

apply

call과 똑같이 함수를 호출하지만 인자를 하나의 배열로 넘긴다.

apply 이나 call은 보통 유사배열 객체에서 배열 매서드를 쓰고 싶을때 주로 사용한다

Array.prototype.slice.call(arguments)

bind

apply 이나 call과 다르게 bind는 함수를 호출하고 실행한 값을 리턴하지 않고
this바인딩이 교체된 함수를 생성해서 리턴한다

function 디스바인드(인자들){
	console.log(this)	
}

const 인자={
	테스트:"테스트"		
}

console.log(디스바인드.bind(인자)) // 디스바인드 
console.log(디스바인드.bind(인자)()) // {테스트:"테스트"}

보통 콜백함수가 this가 다를때 생기는 문제를 해결 할 때 주로 사용한다.

const 사람={
	이름:"김",
	시간이좀필요해(){
	setTimeout(콜백.bind(this),100)	
	}
}

사람.시간이좀필요해(function(){
	console.log(this.이름)
}) // 김

퀴즈

class 과일 {
  constructor(과일이름, 행동) {
    const 이름 = 과일이름;
    this.하자 = 행동;
  }

  행동() {
    this.하자();
  }
}

class 사람 {
  constructor() {
    const 사과 = new 과일("사과", this.먹기);
    사과.행동();
  }

  먹기() {
    this.사과먹기();
  }

  사과먹기() {
    console.log(this);
  }
}

const= new 사람(); // 

0개의 댓글