Front-end/JS

this 와 this binding

ciocio 2022. 4. 2. 18:21

πŸ“Œ this

 

μžμ‹ μ΄ μ†ν•œ 객체 λ˜λŠ” μžμ‹ μ΄ 생성할 μΈμŠ€ν„΄μŠ€λ₯Ό κ°€λ¦¬ν‚€λŠ” 자기 μ°Έμ‘° λ³€μˆ˜ self-referencing-variable 이닀.
this λ₯Ό 톡해 μžμ‹ μ΄ μ†ν•œ 객체 λ˜λŠ” μžμ‹ μ΄ 생성할 μΈμŠ€ν„΄μŠ€μ˜ property λ‚˜ method λ₯Ό μ°Έμ‘°ν•  수 μžˆλ‹€.
단, this κ°€ κ°€λ¦¬ν‚€λŠ” κ°’ (this 바인딩) 은 ν•¨μˆ˜ 호좜 방식에 μ˜ν•΄ λ™μ μœΌλ‘œ κ²°μ •λœλ‹€.
1. 일반 ν•¨μˆ˜ 호좜
2. λ©”μ„œλ“œ 호좜
3. μƒμ„±μž ν•¨μˆ˜ 호좜
4. Function.prototype.apply/call/bind λ©”μ„œλ“œμ— μ˜ν•œ (κ°„μ ‘) 호좜

 


 

πŸ“Ž 일반 ν•¨μˆ˜ 호좜 

기본적으둜 this μ—λŠ” μ „μ—­ 객체(global object)κ°€ λ°”μΈλ”©λœλ‹€.
(μ–΄λ– ν•œ ν•¨μˆ˜[쀑첩 ν•¨μˆ˜, 콜백 ν•¨μˆ˜ 포함]라도 일반 ν•¨μˆ˜λ‘œ 호좜되면 this 에 μ „μ—­ 객체가 λ°”μΈλ”©λœλ‹€.)
strict mode κ°€ 적용되면, this μ—λŠ” undefined κ°€ λ°”μΈλ”©λœλ‹€.

 

console.log(this)                      // μ „μ—­ 객체 window

function foo(){
  console.log("foo's this: ", this);   // window
  function bar(){ 
    console.log("bar's this: ", this); // window
  }
  bar();
}
foo();

 

 

> this 의 λͺ©μ  μžμ²΄κ°€ 객체의 ν”„λ‘œνΌν‹°λ‚˜ λ©”μ„œλ“œλ₯Ό μœ„ν•œ 자기 μ°Έμ‘° λ³€μˆ˜μ΄κΈ° λ•Œλ¬Έμ΄λ‹€.

   μΌλ°˜μ μœΌλ‘œλŠ” 객체의 λ©”μ„œλ“œ λ‚΄λΆ€ λ˜λŠ” μƒμ„±μž ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œλ§Œ μ˜λ―Έκ°€ μžˆκΈ°μ— strict mode μ—μ„œλŠ” μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€ !-!

 

 

πŸ“ 쀑첩 ν•¨μˆ˜, 일반 ν•¨μˆ˜λ‘œ ν˜ΈμΆœν•˜κΈ°

 

var value = 1; 
// var ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•œ μ „μ—­ λ³€μˆ˜ valueλŠ” μ „μ—­ 객체의 ν”„λ‘œνΌν‹°μ΄λ‹€.
// const ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•œ μ „μ—­ λ³€μˆ˜ valueλŠ” μ „μ—­ 객체의 ν”„λ‘œνΌν‹°κ°€ μ•„λ‹ˆλ‹€.
// const value = 1;

const obj = {
  value: 100,
  foo(){
    console.log("foo's this: ", this);               // {value: 100, foo: ⨍}
    console.log("foo's this.value: ". this.value);   // 100
    
    // λ©”μ„œλ“œ λ‚΄μ—μ„œ μ •μ˜ν•œ 쀑첩 ν•¨μˆ˜
    function bar(){
      console.log("bar's this: ", this);             // window
      console.log("bar's this.value: ", this.value); // 1
    }
    
    // λ©”μ„œλ“œ λ‚΄μ—μ„œ μ •μ˜ν•œ 쀑첩 ν•¨μˆ˜λ„ 일반 ν•¨μˆ˜λ‘œ ν˜ΈμΆœν•˜λ©΄ λ‚΄λΆ€μ˜ this μ—λŠ” μ „μ—­ 객체가 λ°”μΈλ”©λœλ‹€.
    bar();
  }
};

obj.foo();

 

 

πŸ“ 콜백 ν•¨μˆ˜, 일반 ν•¨μˆ˜λ‘œ ν˜ΈμΆœν•˜κΈ°

 

var value = 1;

const obj = {
  value: 100,
  foo(){
    console.log("foo's this: ", this);                    // {value: 100, foo: ⨍}
    
    // 콜백 ν•¨μˆ˜ λ‚΄λΆ€μ˜ this μ—λŠ” μ „μ—­ 객체가 λ°”μΈλ”©λœλ‹€.
    setTimeout(function(){
      console.log("callback's this: ", this);             // window
      console.log("callback's this.value: ", this.value); // 1
    }. 100);
  }
};

obj.foo();

 

> κ·Έλ ‡μ§€λ§Œ μ™ΈλΆ€ ν•¨μˆ˜μΈ λ©”μ„œλ“œμ™€ 쀑첩 ν•¨μˆ˜/콜백 ν•¨μˆ˜μ˜ this κ°€ μΌμΉ˜ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것은 

   μ€‘첩 ν•¨μˆ˜/콜백 ν•¨μˆ˜κ°€ 헬퍼 ν•¨μˆ˜λ‘œ λ™μž‘ν•˜κΈ° μ–΄λ ΅κ²Œ λ§Œλ“ λ‹€.

> κ·Έλž˜μ„œ λ©”μ„œλ“œ λ‚΄λΆ€μ˜ 쀑첩 ν•¨μˆ˜/콜백 ν•¨μˆ˜μ˜ this 바인딩과 λ©”μ„œλ“œμ˜ this 바인딩을 μΌμΉ˜μ‹œν‚€λŠ” 방법이 μ‘΄μž¬ν•œλ‹€.

 

 

•  1. λ³€μˆ˜ ν• λ‹Ή

 

var value = 1;

const obj = {
  value: 100,
  foo(){
    // this 바인딩(obj)을 λ³€μˆ˜ that 에 ν• λ‹Ή
    const that = this;
    
    // 콜백 ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ this λŒ€μ‹  that 을 μ°Έμ‘°
    setTimeout(function(){
      console.log(that.value); // 100
    }, 100);
  }
};

obj.foo();

 

•  2. apply, call, bind λ©”μ„œλ“œ μ‚¬μš©ν•΄ 직접 바인딩

 

var value = 1;

const obj = {
  value: 100,
  foo(){
    // 콜백 ν•¨μˆ˜μ— λͺ…μ‹œμ μœΌλ‘œ thisλ₯Ό λ°”μΈλ”©ν•œλ‹€.
    setTimeout(function(){
      console.log(this.value); // 100
    }.bind(this),100);
  }
};

obj.foo();

 

•  3. ν™”μ‚΄ν‘œ ν•¨μˆ˜ μ‚¬μš©

 

var value = 1;

const obj = {
  value: 100,
  foo(){
    // ν™”μ‚΄ν‘œ ν•¨μˆ˜ λ‚΄λΆ€μ˜ thisλŠ” μƒμœ„ μŠ€μ½”ν”„μ˜ thisλ₯Ό 가리킨닀 ❗❗
    setTimeout(() => console.log(this.value), 100); // 100
  }
};

obj.foo();

 

 

πŸ“Ž λ©”μ„œλ“œ 호좜 

λ©”μ„œλ“œ λ‚΄λΆ€μ˜ this μ—λŠ” λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ 객체가 λ°”μΈλ”©λœλ‹€.
β€» λ©”μ„œλ“œ λ‚΄λΆ€μ˜ this λŠ” λ©”μ„œλ“œλ₯Ό μ†Œμœ ν•œ 객체가 μ•„λ‹Œβ— λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ 객체에 λ°”μΈλ”©λœλ‹€.

 

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

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

const me = new Person('Lee');

// getName λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ κ°μ²΄λŠ” meλ‹€.
console.log(me.getName());                          // Lee

Person.prototype.name = 'Kim';

// getName λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ κ°μ²΄λŠ” Person.prototype이닀.
console.log(Person.prototype.getName());            // Kim


// λΈŒλΌμš°μ € ν™˜κ²½μ—μ„œ window.name 은 λΈŒλΌμš°μ € 창의 이름을 λ‚˜νƒ€λ‚΄λŠ” 빌트인 ν”„λ‘œνΌν‹°μ΄κ³ , 기본값은 ''이닀.
// Node.js ν™˜κ²½μ—μ„œ window.name 은 undefined 이닀.

 

 

πŸ“Ž μƒμ„±μž ν•¨μˆ˜ 호좜 

 

function Circle(){
  // μƒμ„±μž ν•¨μˆ˜ λ‚΄λΆ€μ˜ this λŠ” μƒμ„±μž ν•¨μˆ˜κ°€ 생성할 μΈμŠ€ν„΄μŠ€λ₯Ό 가리킨닀.
  this.radius = radius;
  this.getDiameter = function(){
    return 2 * this.radius;
  };
}

// λ°˜μ§€λ¦„μ΄ 5인 Circle 객체λ₯Ό 생성
const circle_5 = new Circle(5);
// λ°˜μ§€λ¦„μ΄ 10인 Circle 객체λ₯Ό 생성
const circle_10 = new Circle(10);

console.log(circle_5.getDiameter());
console.log(circle_10.getDiameter());

 

 

πŸ“Ž Function.prototype.apply/call/bind λ©”μ„œλ“œμ— μ˜ν•œ (κ°„μ ‘) 호좜 

apply, call, bind λ©”μ„œλ“œλŠ” Function.prototype 의 λ©”μ„œλ“œμ΄λ‹€.
apply, call λ©”μ„œλ“œλŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λ©΄μ„œ 첫 번째 인수둜 μ „λ‹¬ν•œ νŠΉμ • 객체λ₯Ό ν˜ΈμΆœν•œ ν•¨μˆ˜μ˜ this 에 λ°”μΈλ”©ν•œλ‹€.
bind λ©”μ„œλ“œλŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šκ³  this 둜 μ‚¬μš©ν•  객체만 μ „λ‹¬ν•œλ‹€.
(κ·Έλž˜μ„œ bind λ©”μ„œλ“œλ‘œ apply, call λ©”μ„œλ“œμ™€ 같은 효과λ₯Ό λ‚΄λ €λ©΄ λͺ…μ‹œμ μœΌλ‘œ ν˜ΈμΆœν•΄μ€˜μ•Όν•œλ‹€.)

 

function getThisBinding(){
  console.log(arguments);
  return this;
}

const thisArg = {a: 1}; // this둜 μ‚¬μš©ν•  객체

// apply λ©”μ„œλ“œλŠ” ν˜ΈμΆœν•  ν•¨μˆ˜μ˜ 인수λ₯Ό λ°°μ—΄λ‘œ λ¬Άμ–΄ μ „λ‹¬ν•œλ‹€.(λ°°μ—΄ λ˜λŠ” μœ μ‚¬ λ°°μ—΄ 객체)
console.log(getThisBinding.apply(thisArg, [1, 2, 3]));
// Arguments(3) [1, 2, 3, callee: ⨍, Symbol(Symbol.iterator): ⨍]
// {a: 1}

// call λ©”μ„œλ“œλŠ” ν˜ΈμΆœν•  ν•¨μˆ˜μ˜ 인수λ₯Ό μ‰Όν‘œλ‘œ κ΅¬λΆ„ν•œ 리슀트 ν˜•μ‹μœΌλ‘œ μ „λ‹¬ν•œλ‹€. 
console.log(getThisBinding.call(thisArg, 1, 2, 3));
// Arguments(3) [1, 2, 3, callee: ⨍, Symbol(Symbol.iterator): ⨍]
// {a: 1}

 

function getThisBinding(){
  return this;
}

// this 둜 μ‚¬μš©ν•  객체
const thisArg = {a: 1};

// bind λ©”μ„œλ“œλŠ” ν•¨μˆ˜μ— this둜 μ‚¬μš©ν•  객체λ₯Ό μ „λ‹¬ν•œλ‹€.
// bind λ©”μ„œλ“œλŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ§€λŠ” μ•ŠλŠ”λ‹€. κ·Έλž˜μ„œ λͺ…μ‹œμ μœΌλ‘œ ν˜ΈμΆœν•΄μ€˜μ•Όν•œλ‹€ !
console.log(getThisBinding.bind(thisArg));   // getThisBinding
console.log(getThisBinding.bind(thisArg)()); // {a: 1}

 

 

πŸ“Lexical Scope 와 this 바인딩

 

Lexical Scope λŠ” ν•¨μˆ˜ μ •μ˜κ°€ ν‰κ°€λ˜μ–΄ ν•¨μˆ˜ 객체가 μƒμ„±λ˜λŠ” μ‹œμ μ— μƒμœ„ μŠ€μ½”ν”„λ₯Ό κ²°μ •ν•œλ‹€.
this 바인딩은 ν•¨μˆ˜ 호좜 μ‹œμ μ— κ²°μ •λœλ‹€.

 

 

πŸ“ 정리

 

ν•¨μˆ˜ 호좜 방식 this 바인딩
일반 ν•¨μˆ˜ 호좜 μ „μ—­ 객체
λ©”μ„œλ“œ 호좜 λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•œ 객체
μƒμ„±μž ν•¨μˆ˜ 호좜 μƒμ„±μž ν•¨μˆ˜κ°€ λ―Έλž˜μ— 생성할 μΈμŠ€ν„΄μŠ€
Function.prototype.apply/call/bind λ©”μ„œλ“œμ— μ˜ν•œ κ°„μ ‘ 호좜 Function.prototype.apply/call/bind λ©”μ„œλ“œμ—
첫 번째 인수둜 μ „λ‹¬ν•œ 객체

 

 

• μ°Έκ³  자료

λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ DEEP DIVE - 이웅λͺ¨

λ°˜μ‘ν˜•