[JavaScript] this


1. this

  • thisλŠ” μ‹€ν–‰ μ»¨ν…μŠ€νŠΈκ°€ 생성 될 λ•Œ ν•¨κ»˜ κ²°μ •λŒ.
  • λ”°λΌμ„œ thisλŠ” ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•  λ•Œ κ²°μ •λ˜λŠ”κ²ƒμ΄λ‹€.

(1) μ „μ—­ κ³΅κ°„μ—μ„œμ˜ this

  • μ „μ—­ κ³΅κ°„μ—μ„œ thisλŠ” μ „μ—­ 객체λ₯Ό κ°€λ₯΄ν‚¨λ‹€.
  • λ”°λΌμ„œ λΈŒλΌμš°μ € ν™˜κ²½μ˜ thisλŠ” windowλ₯Ό κ°€λ₯΄ν‚΄
  • λ”°λΌμ„œ Node.js ν™˜κ²½μ˜ thisλŠ” global을 κ°€λ₯΄ν‚΄
var a = 1;
console.log(a); // 1
console.log(window); // 1
console.log(this.a); // 1
  • 이 μ½”λ“œμ—μ„œλŠ” μ „μ—­ κ³΅κ°„μ—μ„œ μ„ μ–Έν•œ λ³€μˆ˜μ— 1을 ν• λ‹Ήν–ˆλŠ”λ° window , thisκ°€ λͺ¨λ‘ 1이 좜λ ₯됌 β‡’ thisλŠ” μ „μ—­κ°μ²΄μ΄λ―€λ‘œ window 객체가 λ‚˜μ™€μ•Όν•œλ‹€ 근데 1이 좜λ ₯됌
  • μ—¬κΈ°μ„œ μ€‘μš”ν•œ 것은 μ „μ—­λ³€μˆ˜λ₯Ό μ„ μ–Έν•˜λ©΄ JavaScript 엔진은 μ „μ—­ 객체의 ν”„λ‘œνΌν‹°λ‘œ ν• λ‹Ήλœλ‹€
  • μ΄μœ λŠ” λ³€μˆ˜ a에 μ „μ—­κ°μ²΄μ—μ„œ μ „μ—­ μŠ€μ½”ν”„ L.E , μ„ μ–Έν•œ ν”„λ‘œνΌν‹° aλ₯Ό λ°œκ²¬ν•΄μ„œ κ·Έ 값을 λ°˜ν™˜ν–ˆκΈ° λ•Œλ¬Έμ— 1이 좜λ ₯λœκ²ƒμ΄λ‹€

λ”°λΌμ„œ window ν”„λ‘œνΌν‹°μ— 할당해도 var둜 μ„ μ–Έν•œ κ²°κ³Όκ°€ λ˜‘κ°™λ‹€

var a = 1;
window b = 2;
console.log(a,window a, this.a);// 1 1 1
console.log(b,window b, this.b);// 2 2 2

(2) λ©”μ„œλ“œλ‘œμ„œ ν˜ΈμΆœν•  λ•Œ λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œμ˜ this

  1. ν•¨μˆ˜ 호좜: 독립 적인 κΈ°λŠ₯ μˆ˜ν–‰
  2. λ©”μ„œλ“œ 호좜: μžμ‹ μ„ ν˜ΈμΆœν•œ λŒ€μƒ 객체에 κ΄€ν•œ λ™μž‘ μˆ˜ν–‰
var func = function (x) {
  console.log(this, x);
};
// (1) ν•¨μˆ˜ 호좜

func(1);

//WindowΒ {0: Window, window: Window, self: Window, document: document, name: '', location: Location, …}
var obj = {
  method: func,
};

// (2) λ©”μ„œλ“œ 호좜 (점 ν‘œκΈ°λ²•)

obj.method(2);
// {method: Ζ’}method: Ζ’ (x)[[Prototype]]: Object 2

// (3) λ©”μ„œλ“œ 호좜 (λŒ€κ΄„ν˜Έ ν‘œκΈ°λ²•)

var obj2 = {
  method: function (x) {
    console.log(this, x);
  },
};

obj2["method"](2);
  • μ‰½κ²Œ ꡬ뢄 ν•˜λŠ” 방법은 ν•¨μˆ˜ μ•žμ— 점(.)이 μžˆλƒ 없냐 λŒ€κ΄„ν˜Έκ°€ μžˆλƒ μ—†λƒμ˜ νŒλ‹¨μœΌλ‘œ μ‰½κ²Œ ꡬ뢄 κ°€λŠ₯ν•˜λ‹€

λ”°λΌμ„œ 점 ν‘œκΈ°λ²•μ—μ„  λ§ˆμ§€λ§‰ 점 μ•žμ— λͺ…μ‹œλœ 객체가 thisλΌλŠ” 것이닀

(3) ν•¨μˆ˜ ν˜ΈμΆœλ‘œμ„œ ν˜ΈμΆœν•  λ•Œ ν•¨μˆ˜ λ‚΄λΆ€μ˜ this

var obj1 = {
  outer: function () {
    console.log(this); // (1) obj1
    var innerFunc = function () {
      console.log(this); // (2) window // (3) obj2
    };
    innerFunc();
    var obj2 = {
      innerMethod: innerFunc,
    };
    obj2.innerMethod();
  },
};
obj1.outer();

thisλ₯Ό 이해 ν•˜κΈ° μœ„ν•œ μ½”λ“œ μ‹€ν–‰ κ³Όμ •

  • 객체λ₯Ό μƒμ„±ν•˜κ³  outer() ν”„λ‘œνΌν‹°λ₯Ό obj1에 ν• λ‹Ή
  • obj.outer() 호좜
  • obj.outer()의 μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ 생성 및 innerFunc와obj2λ₯Ό Hoisting
  • console.log(this)μ—μ„œ ν•΄λ‹Ή thisλ₯Ό λ°”μΈλ”©ν•œλ‹€
  • 점 ν‘œκΈ°λ²•μœΌλ‘œ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν–ˆμœΌλ‹ˆ (1)은 점 μ•žμ˜ 객체 obj1λ₯Ό 바인딩
  • innerFunc에 읡λͺ…ν•¨μˆ˜λ₯Ό ν• λ‹Ήν•˜κ³  호좜
  • innerFunc의 μ‹€ν–‰ μ»¨ν…μŠ€νŠΈ 생성 및 Hoistng
  • console.log(this)μ—μ„œ ν•΄λ‹Ή thisλ₯Ό λ°”μΈλ”©ν•œλ‹€
  • 이 this ν˜ΈμΆœμ—” 점 ν‘œκΈ°λ²•μœΌλ‘œ ν˜ΈμΆœλ˜μ§€ μ•Šμ•˜μœΌλ‹ˆ 전역객체 windowκ°€ λ°”μΈλ”©λœλ‹€
  • obj2λŠ” innerMethod ν”„λ‘œνΌν‹°μ— innerFuncλ₯Ό ν• λ‹Ήν•˜κ³  λ‹€μ‹œ 호좜
  • μ—¬κΈ°μ„  또 호좜 μ‹œ innerMethodμ•žμ— obj2의 μ ν‘œκΈ°λ‘œ 호좜 ν–ˆμœΌλ‹ˆ obj2κ°€ λ°”μΈλ”©λœλ‹€

μ£Όλ³€ ν™˜κ²½μ€ μ€‘μš”ν•˜μ§€ μ•Šκ³  ν•΄λ‹Ή ν•¨μˆ˜ 호좜 뢀뢄에 λ”°λΌμ„œ thisλŠ” 점 ν‘œκΈ° 인지 λŒ€κ΄„ν˜Έ ν‘œκΈ°λ₯Ό 확인해야 thisκ°€ μ–΄λ–€ κ±Έ λ°”μΈλ”©ν•˜λŠ”μ§€ μ•Œ 수 μžˆλ‹€

(1) λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œ this 우회 방법

  • this에 λ³€μˆ˜λ₯Ό ν™œμš©ν•˜λŠ” 방법이 μžˆλ‹€

(2) this 바인딩을 ν•˜μ§€ μ•ŠλŠ” ν•¨μˆ˜

  • ES6μ—μ„œ ν™”μ‚΄ν‘œ ν•¨μˆ˜λŠ” this 바인딩 κ³Όμ • μžμ²΄κ°€ λΉ μ Έμ„œ μƒμœ„ μŠ€μ½”ν”„μ˜ thisλ₯Ό ν™œμš© ν•  수 μžˆλ‹€. λ”°λΌμ„œ ES6λΆ€ν„΄ μš°νšŒλ²•μ΄ λΆˆν•„μš”ν•˜λ‹€

(4) 콜백 ν•¨μˆ˜ ν˜ΈμΆœμ—μ„œμ˜ this

  • 콜백 ν•¨μˆ˜λ„ ν•¨μˆ˜λΌ 기본적으둜 thisκ°€ 전역객체λ₯Ό μ°Έμ‘°ν•˜μ§€λ§Œ, μ œμ–΄κΆŒμ„ 받은 ν•¨μˆ˜μ—μ„œ μ½œλ°±ν•¨μˆ˜μ— λ³„λ„λ‘œ thisκ°€ 될 λŒ€μƒμ„ μ§€μ •ν•œ κ²½μš°λŠ” κ·Έ λŒ€μƒμ„ μ°Έμ‘°ν•˜κ²Œ λœλ‹€.
setTimeout(function () {
  console.log(this), 300;
}); // (1) : window

[1, 2, 3, 4, 5].forEach(function (x) {
  console.log(this, x); // (2) : window
});

document.body.innerHTML += '<button id ="a">클릭</button>';
document.body.querySelector("#a").addEventListener("click", function (e) {
  console.log(this, e); // (3) : document.body.querySelector('#a')
});
  • λ‹€λ§Œ 콜백 ν•¨μˆ˜μ—μ„  thisκ°€ 무쑰건적이진 μ•Šλ‹€

(5) μƒμ„±μž ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œμ˜ this

  • μƒμ„±μž ν•¨μˆ˜μ—μ„œ 호좜된 경우의 thisλŠ” μƒˆλ‘œ λ§Œλ“€ ꡬ체적인 μΈμŠ€ν„΄μŠ€ μžμ‹ μ΄λ‹€
var Cat = function (name, age) {
  this.bark = "μ•Όμ˜Ή";
  this.name = name;
  this.age = age;
};

var choco = new Cat("μ΄ˆμ½”", 7); // (1): Cat { bark: 'μ•Όμ˜Ή', name: 'μ΄ˆμ½”', age: 7 }
var nabi = new Cat("λ‚˜λΉ„", 5); //  (2): Cat { bark: 'μ•Όμ˜Ή', name: 'λ‚˜λΉ„', age: 5 }
console.log(choco, nabi);

2. λͺ…μ‹œμ  this 바인딩

(1) call

  • λ©”μ„œλ“œ 호좜 주체인 ν•¨μˆ˜λ₯Ό μ¦‰μ‹œ μ‹€ν–‰ν•˜λŠ” λͺ…λ Ή
  • call λ©”μ„œλ“œμ˜ 첫번째 인자λ₯Ό this λ°”μΈλ”©ν•˜κ³  λ‚˜λ¨Έμ§€ μΈμžλ“€μ„ ν˜ΈμΆœν•  ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λ‘œ ν• λ‹Ή
  • call λ©”μ„œλ“œλŠ” μž„μ˜μ˜ 객체λ₯Ό this둜 지정 κ°€λŠ₯함
var obj = {
    a:1,
    method:function(x,y){
        console.log(this.a,x,y);
    }
};

obj.method(2,3);
obj.method.call({a:4},5,6);

// 1 2 3
// 4 5 6

[Done] exited with code=0 in 0.051 seconds

call λ©”μ„œλ“œ ν™œμš©

  • μœ μ‚¬λ°°μ—΄κ°μ²΄μ— λ°°μ—΄ λ©”μ„œλ“œ μ μš©ν• λ•Œ
  • argument ,NodeList에 λ°°μ—΄ λ©”μ„œλ“œ μ μš©ν• λ•Œ
  • λ¬Έμžμ—΄μ— λ°°μ—΄ λ©”μ„œλ“œ μ μš©ν• λ•Œ
var obj1 = {
  0: "a",
  1: "b",
  2: "c",
  length: 3,
};

Array.prototype.push.call(obj1, "d");
console.log(obj1);

var arr1 = Array.prototype.slice.call(obj1);
console.log(arr1);

(2) apply

  • κΈ°λŠ₯적으둠 callκ³Ό 동일함
  • 차이점은 call λ©”μ„œλ“œλŠ” 첫번째 인자λ₯Ό μ œμ™Έν•œ λͺ¨λ“  μΈμžλ“€μ„ 맀개 λ³€μˆ˜λ‘œ μ§€μ •ν•˜μ§€λ§Œ apply λ©”μ„œλ“œλŠ” λ‘λ²ˆμ§Έ 인자λ₯Ό λ°°μ—΄λ‘œ λ°›μ•„μ„œ 처리
var func = function(a,b,c){
    console.log(this,a,b,c);
}

func.apply({x:1},[4,5,6]);

var obj = {
    a:1,
    method:function(x,y){
        console.log(this.a,x,y);
    }
};

obj.method.call({a:4},5,6);

// { x: 1 } 4 5 6
// 4 5 6

[Done] exited with code=0 in 0.052 seconds

ES6 λŒ€μ•ˆ

  • Array.from
var obj = {
    0:'a',
    1:'b',
    2:'c',
    length:3,
}

var arr =Array.from(obj);
console.log(arr);

// [ 'a', 'b', 'c' ]

[Done] exited with code=0 in 0.045 seconds

apply λ©”μ„œλ“œ ν™œμš©

  • μ΅œλŒ€/μ΅œμ†Œκ°’ κ΅¬ν•˜λŠ” μ½”λ“œ
var numbers = [10, 20, 3, 16, 45];
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);
console.log(max, min);

ES6 λŒ€μ•ˆ

  • Spread Operator
var numbers = [10, 20, 3, 16, 45];
var max = Math.max(...numbers);
var min = Math.min(...numbers);
console.log(max, min);

(3) bind

  • callκ³Ό λΉ„μŠ·ν•˜μ§€λ§Œ μ¦‰μ‹œ ν˜ΈμΆœν•˜μ§€ μ•Šκ³  λ„˜κ²¨ 받은 this 및 μΈμˆ˜λ“€μ„ λ°”νƒ•μœΌλ‘œ μƒˆλ‘œμš΄ ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•˜κΈ°λ§Œ 함
  • bind의 핡심은 thisλ₯Ό 미리 적용 , λΆ€λΆ„ 적용 ν•¨μˆ˜λ₯Ό κ΅¬ν˜„
var func = function(a,b,c,d){
    console.log(this,a,b,c,d);
}

func(1,2,3,4);

var bindFunc1 = func.bind({x:1});
bindFunc1(5,6,7,8);

// Window{...} 1 2 3 4
// { x: 1 } 5 6 7 8

[Done] exited with code=0 in 0.061 seconds

ES6 λŒ€μ•ˆ : ν™”μ‚΄ν‘œ ν•¨μˆ˜

  • ν™”μ‚΄ν‘œ ν•¨μˆ˜λŠ” thisλ₯Ό λ°”μΈλ”©ν•˜λŠ” 과정이 μ œμ™ΈλμŒ
  • λ‚΄λΆ€μ˜ thisλŠ” μ—†κ³  μ ‘κ·Όν•˜λ©΄ κ°€μž₯ κ°€κΉŒμš΄ μŠ€μ½”ν”„μ²΄μΈμ˜ this에 μ ‘κ·Ό
  • λ”°λ‘œ this μš°νšŒν•  ν•„μš”λ„ μ—†κ³  call/apply/bindλ₯Ό 적용 ν•  ν•„μš” μ—†μŒ

(4) 정리

  • μ „μ—­ κ³΅κ°„μ—μ„œμ˜ this : 전역객체( window , global..)
  • ν•¨μˆ˜ λ©”μ„œλ“œμ—μ„œμ˜ this : λ©”μ„œλ“œ 호좜 주체 μ°Έμ‘°
  • ν•¨μˆ˜ ν˜ΈμΆœμ—μ„œμ˜ this : ν•¨μˆ˜ 호좜 주체 μ°Έμ‘° (기본적으둠 μ „μ—­ 객체 μ°Έμ‘°)
  • 콜백 ν•¨μˆ˜μ—μ„œμ˜ this : 콜백 ν•¨μˆ˜μ˜ μ œμ–΄κΆŒμ„ λ„˜κ²¨λ°›μ€ ν•¨μˆ˜ 주체 μ°Έμ‘° (기본적으둠 μ „μ—­ 객체 μ°Έμ‘°)
  • μƒμ„±μž ν•¨μˆ˜μ—μ„œμ˜ this : μΈμŠ€ν„΄μŠ€ λŒ€μƒ μ°Έμ‘°

ν™”μ‚΄ν‘œ ν•¨μˆ˜λ₯Ό μ“°λ©΄ this λͺ…μ‹œμ  바인딩을 적용 ν•  ν•„μš”κ°€ μ—†λ‹€