this의 값은 함수를 호출한 방법이 결정합니다.

함수를 호출하는 방법에는 어떻게 있을까요?

  • 전역에서의 this
  • 함수에서의 this
  • call, apply
  • 메소드에서의 this
  • 내부함수, 콜백함수에서의 this

전역에서의 this

console.log(this); // window {...}

this.a = 'A';
console.log(window.a) // 'A'

this.hello = 'world';
console.log(window.hello) // 'world'

cat = "Meow";
console.log(window.cat) // 'Meow'
console.log(cat) // 'Meow'

this는 기본적으로 전역 객체인 window에 바인딩됩니다.


함수에서의 this

function foo() {
    return this;
}
console.log(foo()); // window {...}

dog = "bow";
function bar () {
    return this.dog;
}
console.log(bar()); // bow;

함수안에 있는 this가 window객체를 가르키고 있다는 걸 확인할 수 있습니다.


call, apply

call, apply를 이용해서 this를 window가 아닌 다른 객체의 속성 값을 사용할 수 있게 할 수 있습니다.

world = 'world'
function hello () {
    return this.world
}
console.log(hello()); // 'world'

const hello2 = {
    world: 'world~!'
}
console.log(hello.call(hello2)) // 'world~!';
console.log(hello.apply(hello2)) // 'world~!';

처음의 매개변수가 this를 어디 객체에 속하게 할 것인지 결정합니다. 뒤에 오는 것들은 실행함수의 매개변수로 들어갈 값들입니다. call과 apply의 차이점이 있습니다. call은 낱개로 값을 전달하고 apply는 배열을 이용해서 매개변수에 전달합니다.

// call   somthing.call(thisArgu, parameter1, parmeter2, ...)
// apply  somthing.apply(thisArgu, [parameter1, parmeter2, ...]);
function sum (a, b) {
    return this.one + this.two + a + b;
}
const number = {
    one: 1,
    two: 2,
}
let callResult = sum.call(number, 5, 15);
console.log(callResult) // 23
let applyResult = sum.apply(number, [3, 4]);
console.log(applyResult) // 10

메소드에서의 this

객체에서 생성한 함수, 메소드에 내부에 있는 this는 그 객체에 할당됩니다.

const foo = {
      a: 'A',
    objFunc: function () {
      return this;
    }
}
let result = foo.objFunc();
console.log(result); // {a: 'A', objFunc: ƒ}

const bar = {
    num1: 5,
    num2: 30,
    sum: function () {
        return this.num1 + this.num2
    }
}
result = bar.sum();
console.log(result); // 35

메소드 호출도 call과 apply를 이용해서 다른 객체의 속성을 이용할 수 있습니다.

const foo = {
    character: 'a',
      output: function () {
        return this.character;
    }
}
let normal = foo.output();
console.log(normal); // 'a'

const bar = {
    character: '가'
}
let callResult = foo.output.call(bar);
console.log(callResult); // '가'

생성자 함수로 생성한 인스턴스는 만들어진 인스턴스가 this로 결정됩니다.

const Basicwizard (wand, magic) {
    this.wand = wand;
      this.magic = magic;
      this.cast = function () {
        return `Use ${this.magic} with ${this.wand}`;
}

const fireWizard = new Basicwizard('firewand', 'fireball');
console.log(fireWizard.cast()); // Use fireball with firewand

내부함수와 콜백함수에서의 this

내부함수와 콜백함수에서의 this는 window를 가르키고 있다. 메소드를 실행 시키면 this는 undefined를 반환합니다.

var foo = {
    a: 'Hello World',
    b: function () {
        console.log(this, 'outer'); // {a: 'Hello world', b: f} outer 
            function inner () {
            console.log(this, 'inner'); // window {...} inner
            return this.a;
        }
        return inner();
    }
}
let result = foo.b();
console.log(result) // undefined;

result의 값이 undefined가 아니고 Hello World로 나오게 할려면 어떻게 해야될까요?
외부함수에서 변수 선언, bind, 화살표 함수(arrow function)을 이용하는 방법이 있습니다.

// 외부함수 변수 선언
var foo = {
    a: 'Hello World',
    b: function () {
        var that = this; // 변수 선언

        function inner () {
          return that.a; // 변수 활용
        }
        return inner();
    }
}
var result = foo.b();
console.log(result); // Hello World
// bind
var foo = {
    a: 'Hello World',
    b: function () {
        function inner () {
          return this.a;
        }
        return inner.bind(this)(); // bind로 this를 결정해주고 함수실행
    }
}
var result = foo.b();
console.log(result); // Hello World

bind는 call, apply와 차이점은 call과 apply는 this는 결정는 동시에 실행하고, bind는 객체만 결정해줍니다. 실행은 따로 해야합니다.