Dynamic Binding, This의 값 : 조작/호출

김종현·2023년 3월 15일
0

일일 공부

목록 보기
4/4

Dynamic Binding

선요약
-함수는 다양한 환경에서 호출될 수 있다
-함수의 호출 환경에 따라 this는 동적으로 세팅된다(dynamic binding)
-bind, apply, call 등으로 this가 가리키는 것을 조작할 수 있다.

this 의 값
-global scope 에서 사용될 때 : 전역 객체(window 객체)
-함수에서 사용될 때 : 전역 객체
-객체에 속한 메소드에서 사용될 때 : 메소드가 속한 객체
-객체에 속한 메소드의 내부함수에서 사용될 때 : 전역 객체
-생성자에서 사용될 때 : 생성자로 인해 생성된 새로운 객체
ex) function Person(){}, var p = new Person(); // this : Person

함수가 호출되는 상황 4가지

1) 함수 직접 호출 :

  • myFunc()

2) 메서드 호출 : 객체의 메서드 호출

  • o.method()

3) 생성자 호출 : 생성자 함수 호출

  • function person(){...}, const p = new Person()

4) 간접 호출 : call, apply(함수 객체 메서드) 등으로 함수 간접 호출

  • f.call(a,b)

※콜백 함수의 호출

  • 특정 함수가 실행 될 때 해당 함수 실행 이후에 실행되거나, 특정 조건에서 실행되도록 ‘예약’하고 싶을 때 주로 사용
  • 보통 다른 함수의 인자로 보내지는 함수를 의미
function myFunc(){...}
myFunc();
//함수 직접 호출  
                  
const o = {
  name : 'kim',
  printName : function(){console.log(this.name),}
o.printName();
//메서드 호출 
                  
funtion Person(name){
  this.name = name
  this.printName = function(){
    console.log(this.name)}
}
const p = new Person('kim')
//생성자 호출

setTimeout(p.printName.bind(p), 1000)
//간접 호출
//bind() this변수에 해당되는 객체를 메서드에 묶어주는 함수
// 위의 p 객체를 printName메서드에 묶어줘서 printName의 this값이 p의 this값을 갖도록 함(이 경우 p)

Dynamic binding 예시

let o = {
  name : 'kim'
  	f1 : () =>{
    console.log("[f1] this : ", this);
  },
    // f1 : '화살표 함수' 호출 시 this는 함수가 생성된 환경을 가리키도록 **고정된다**
    
 	f2 : function (){
      console.log("[f2] this : ", this);
  },
};
	// f2 : '일반 함수' 호출 시 this는 호출된 환경을 가리키며 this는 **동적으로 바뀔 수 있다.**
	// f2 : 객체의 메서드로 호출될 때 객체가 this로 할당된다.

o.f1(); // this : global
o.f2(); // this : o

setTimeout(o.f1, 10); // this : global
setTimeout(o.f2, 20); // this : global   

https://velog.io/@padoling/JavaScript-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98%EC%99%80-this-%EB%B0%94%EC%9D%B8%EB%94%A9
https://sangjuntech.tistory.com/24
화살표 함수를 호출시에는 this라는 변수가 존재하지 않으므로 상위 스코프에서 탐색을 하게 되어 스코프가 global이 된다.

this의 조작

let o = {
  name : 'kim',
  printName : function(){console.log("나는 ", this.name);},
  };
  
  o.printName(); // 나는 kim
  - 객체에 속한 메소드에서 사용될 때 this 는 메소드가 속한 객체를 가리킨다
  setTimeout(o.printName, 10); // 나는 undefined 
  - 객체 내 메서드의 내부의 this는 전역 객체를 가리킨다
  setTimeout(o.printName.bind(o), 20); // 나는 kim
  - bind 함수를 이용해 this변수가 o를 가리키도록 컨텍스트를 동적 바인딩한다.

-bind, call, apply 등의 함수로 조작한다
-setTimeout은 함수 호출과는 다른 콜백 호출이다
-prinName 메서드는 bind 함수를 이용해 this변수가 o를 가리키도록 컨텍스트를 동적 바인딩한다.

this의 고정

  1. 화살표 함수로 고정하기
  2. bind, apply, call 메서드 사용
    1) bind
/* 생성자 함수 방식 */
function createObject() {
  this.myFunc = function () {
    console.log("myFunc this:", this);
    return function () { console.log("myFunc return this:", this) };
  };
}

const o = new createObject();
o.myFunc().bind(o)(); // bind 메서드를 사용해 o객체로 고정시킵니다.
// myFunc        this: createObject {...}
// myFunc return this: createObject {...}

/* 객체 리터럴 방식 */
const o = {
  myFunc: function () {
    console.log("myFunc this:", this)
    return function () { console.log("myFunc return this:", this) }
  },
};

o.myFunc().bind(o)(); // bind 메서드를 사용해 o객체로 고정 그리고 함수를 실행
// myFunc        this: myFunc {...}
// myFunc return this: myFunc {...}

2) apply, call
-call 메서드는 인수 목록을 받고, apply 메서드는 인수 배열을 하나 받는다.
ex) call(this, var1, var2, var3, …) / apply(this, [ el, el2, el3, … ])

/* 생성자 함수 방식 */
function createObject() {
  this.myFunc = function () {
    console.log("myFunc this:", this);
    return function () { console.log("myFunc return this:", this) };
  };
}

const o = new createObject();
o.myFunc().call(o, null);  // call  메서드를 사용해 o객체로 고정시킨 후 함수 실행
// myFunc        this: createObject {...}
// myFunc return this: createObject {...}
o.myFunc().apply(o, null); // apply 메서드를 사용해 o객체로 고정시킨 후 함수 실행
// myFunc        this: createObject {...}
// myFunc return this: createObject {...}

/* 객체 리터럴 방식 */
const o = {
  myFunc: function () {
    console.log("myFunc this:", this)
    return function () { console.log("myFunc return this:", this) }
  },
};

o.myFunc().call(o, null);  // call  메서드를 사용해 o객체로 고정시킨 후 함수 실행
// myFunc        this: myFunc {...}
// myFunc return this: myFunc {...}
o.myFunc().apply(o, null); // apply 메서드를 사용해 o객체로 고정시킨 후 함수 실행
// myFunc        this: myFunc {...}
// myFunc return this: myFunc {...}

bind, call, apply는 일반 함수 호출에도 원하는 객체를 가리킬 수 있다.

const o = {
    name: "Elice",
}

function myFunc() {
  console.log(this);
}

myFunc()              // window {...}
myFunc.bind(o)()      // {name: 'Elice'}
myFunc.call(o, null)  // {name: 'Elice'}
myFunc.apply(o, null) // {name: 'Elice'}

this : 화살표 함수 vs 일반 함수

1) 화살표 함수
-익명 함수로만 만들 수 있다.
-생성자로 사용할 수 없다.
-스스로의 this, argument 를 가지지 않는다.
-return하지 않아도 값이 반환된다.

화살표 함수의 this는 '함수가 정의된 스코프에 존재하는' this 를 가리킨다. 즉 자신의 상위에 있는 스코프의 this를 가리킨다.

-생성될 때 this 가 결정되며 이 값을 계속 유지한다.
-화살표 함수가 어떻게 사용되건, 호출되건, this 는 바뀌지 않는다.

  • 이때 bind, call, apply 로도 this 값을 바꿀 수 없다.
  • 따라서 절대로!! 메서드를 화살표 함수로 정의하면 안된다! 태생부터 this가 window를 가리키게 된다.
  • setTimeout등 this가 바뀌는 상황에서 유용하게 쓸 수 있다.

2) 일반 함수
-일반 함수의 this는 '새롭게 생성된 실행 컨텍스트'를 가리킨다. 즉 함수가 호출된 컨텍스트를 가리킨다.

  • bind, call, apply로 this 값을 바꿀 수 있다.
const o = {
  method(){
    console.log("context : ", this) // o
    let f1 = function (){
      console.log("[f1] this : ", this)
    }
    let f2 = () => console.log("[f2] this : ", this)
    f1() // global 만약 strict mode일 경우 undefined
    f2() // o
  },
};
o.method()

-일반 함수 f1()은 실행될 때 새로운 컨텍스트를 생성한다.
- 이때 f1에 바인딩된 컨텍스트가 없으므로 this는 global을 가리킨다.??

  • o.method()가 실행된 곳이 전역 스코프이므로 호출된 f1의 this는 window가 되기 때문이다.

-화살표 함수 f2()의 this는 그 함수를 호출하는 환경을 가리킨다. 즉, 이때 this 변수는 부모의 컨텍스트를 가리키므로 this는 o가 된다.

화살표 함수의 this 성질을 활용한 코드

-어떤 경우에도 this 값을 일정하게 유지해야 할 때 사용

window.name = 'Kim'
let o = {name : 'lee'}

let arrowFunction = (prefix) => console.log(prefix + this.name)

arrowFunction('Dr. ') // Dr. Kim
arrowFunction.bind(o)('Dr. ') // Dr. Kim
arrowFunction.call(o, 'Dr. ') // Dr. Kim
arrowFunction.apply(o, 'Dr. ') // Dr. Kim
profile
나는 나의 섬이다.

0개의 댓글