Javascript

javascript - this

유개나발 2019. 8. 12. 19:18

자바스크립에서 this는 함수의 현재 실행 문맥이다.

 

strict-mode 에서의 this

function nonStrict() {
    return this
}

function strict() {
    'use strict'
    return this
}

console.log(nonStrict()) // window
console.log(strict()) // undefined
console.log(window.strict()) // window

함수 실행에서의 실행 문맥은 전역 객체이다. 엄격모드에의 this는 undefined이다. 하지만 일반객체냐 전역객체에 따라 this 의 결과가 달라지지만 window를 함수 호출 앞에 붙여주면 해결됩니다.

 

 

생성자 함수/ 객체에서의 this

function Fruit(color, flavor) {
    this.color = color
    this.flavor = flavor
    this.fuc = function () {
        return this
    }
}

const strawberry = new Fruit('red', 'sweet')

console.log(strawberry.color) // red
console.log(strawberry.fuc()) // strawberry

new 키워드로 객체를 생성했을 경우 생성자 함수 내의 this는 new를 통해 만들어진 새로운 변수가 됩니다.

 

const banana = Fruit('yellow', 'sweet')

console.log(banana.color) // error
console.log(banana.fuc()) // error

new 키워드가 없으면 일반적인 함수와 동일하게 동작하므로, Fruit 함수내의 this는 window 객체가 됩니다. 하지만 banana가 함수 실행의 결과값이 할당되므로 각 property 를 가져올 수 없습니다.

 

 

일반객체

const fruit = {
  name: 'apple',
  color: red,
  getName: function() {
    return this.name
  },
}
console.log(fruit.getName()) // apple

const otherFruit = fruit
otherFruit.name = 'cherry'

console.log(fruit.getName()) // cherry
console.log(otherFruit.getName()) // cherry

otherFruit.name을 cherry 설정한 뒤 fruit.getName() 호출하면 그 결과는 cherry. 그 이유는 otherFruit 은 fruit 의 레퍼런스 변수이므로 하나(otherFruit)를 변경하면 다른 하나(fruit)도 변경됩니다. 이를 피하기 위해서는 Object.assign()메서드(ES6 지원)를 이용하여 완전히 별도의 객체로 만들어야 합니다.

const newFruit = Object.assign({}, fruit)
newFruit.name = 'cherry'

console.log(fruit.getName()) // apple
console.log(newFruit.getName()) // cherry

 

bind, arrow function

 

생성자 함수 안에 또 다른 함수가 있는 경우

function Family(firstName) {
  this.firstName = firstName
  const names = ['yuna', 'jeongwon']
  names.map(function(value, index) {
    console.log(value + ' ' + this.firstName)
  })
}

const Shin = new Family('Shin')

// yuna undefined
// window
// jeongwon undefined
// window

map 메서드의 서브루틴은 호출될때 map 의 context(this)로 바인드 되지 않습니다. 바인드 되지 않았다는 것은 실행문맥이 전역이라는 것이고 실행문맥이 전역이란 말은 (비엄격모드에서) 서브루틴 내 this가 window라는 것 입니다.

 

실행 문맥을 Family로 지정하려면 간단하게 별도의 상수를 지정해주면 됩니다.

function Family(firstName) {
  this.firstName = firstName
  const names = ['yuna', 'jeongwon']
  const that = this
  names.map(function(value, index) {
    console.log(value + ' ' + that.firstName)
  })
}
const Shin = new Family('Shin')

// yuna Shin
// jeongwon Shin

상수를 만들어주기 귀찮으면 bind 라는 메서드를 사용합니다.

function Family(firstName) {
  this.firstName = firstName
  const names = ['yuna', 'jeongwon']
  names.map(
    function(value, index) {
      console.log(value + ' ' + this.firstName)
    }.bind(this)
  )
}
const Shin = new Family('Shin')

 

bind도 귀찮으면 이제 arrow function을 사용해줍니다.

function Family(firstName) {
  this.firstName = firstName
  const names = ['yuna', 'jeongwon']

  names.map((value, index) => {
    console.log(value + ' ' + this.firstName)
  })
}
const Shin = new Family('Shin')

일반 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다.

 

하지만 화살표 함수는 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정된다. 동적으로 결정되는 일반 함수와는 달리 화살표 함수의 this 언제나 상위 스코프의 this를 가리킨다.

 

 

참고자료

https://blueshw.github.io/2018/03/12/this/