[Article] Javascript This

kcm dev blog·2021년 8월 25일
0

Article

목록 보기
2/2
post-thumbnail

객체

property(상태(state)를 나타냄) + 메서드(동작(behavior)
을 나타냄을 하나의 논리적인 단위로 묶은 복합적인 자료구조

메서드는 자신이 속한 객체의 상태 즉, 프로퍼티를 참조하고 변경할 수 있어야 한다. 이때 객체의 프로퍼티를 참조하려면 먼저 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 한다

생성자 함수로 인스턴스를 생성하려면 먼저 생성자 함수가 존재해야 한다. 그리나 생성자 함수를 정의하는 시점에서는 인스턴스를 생성하기 전이므로 생성자 함수가 생성할 인스턴스를 가리키는 식별자를 모른다. 따라서 인스턴스를 가리키는 특수한 식별자가 필요하고, javascript에서는 this를 제공한다

// 생성자 함수 
function Circle(radius){
  ???.radius=radius;
  //인스턴스(circle)의 값을 초기화하기 위해 인스턴스를 가리키는 식별자가 필요하다. 그리나 정의할 때 당시에는 어떤 인스턴스를 가리킬지 모르므로 공통의 식별자를 사용할 필요가 있고, 그것이 this이다.

}
const circle=new Circle(5);

this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기참조변수

this

javascript에서 this는 함수가 호출되는 방식에 따라 this에 바인딩 될 값이 달라진다.(strict mode또한 this 바인딩에 영향을 준다)

// 유형 1. 전역에서 .. this는 전역 객체 window를 가리킨다
console.log(this); // window

// 유형 2. 일반 함수 내부에서 .. this는 전체 객체 window를 가리킨다
// (strict mode에서는 일반함수에서 this 사용시 undefined가 바인딩 된다)
function square(number){
  console.log(this); // window
  return number*number;
}

// 유형 3. 객체 리터럴에서 .. 매서드 내부에서 this는 메서드를 호출한 객체를 가리킨다
const person={
  name:'lee',
  getName(){
    console.log(this) // person
    return this.name // lee
  }
}

// 유형 4. 생성자 함수에서 .. this는 생성자 함수가 생성할 인스턴스를 가리킨다.
function Person(name){
  this.name=name;
  console.log(this);// Person {name:'kim'}
}
const myPerson=new Person('kim');

// 유형 5. Function.prototype.apply/call/bind 메소드 .. 에 의한 간접 호출
// foo 함수 내부의 인수에 의해 결정된다.
const bar={name:'bar'}
foo.call(bar);//bar
foo.apply(bar);//bar
foo.bind(bar)();//bar

다만 .. this객체의 프로퍼티나 메소드를 참조하기 위한 자기 참조 변수이기 떄문에 일반적으로 객체 메소드 내부 또는 생성자 함수 내부에서만 의미가 있다. 따라서 strict mode가 적용된 경우 일반함수에서 this를 사용하면 undefined가 바인딩 된다.

함수 호출 방식과 this 바인딩

  1. 일반함수 호출
  • this에는 디폴트로 전역 객체(window)가 바인딩 된다.
  • this는 객체의 프로퍼티나 메소드를 참조하기 위한 자기참조변수 이기 때문에 일반 함수에서의 사용은 무의미 하다. 따라서 strict mode에서는 undefined가 바인딩 된다.
function foo(){
  console.log(this)//window
}
foo()

function foo(){
  'use strict'

  console.log(this)//undefined
}
foo()
  • 메소드에서 바인딩 된 this는 객체를 가리킨다
  • 객체 내부에 선언된 중첩 함수의 경우 전역 객체(window)가 바인딩 된다.
  • 콜백 함수 등 어떠한 함수 안에 this를 호출하더라도, 해당 함수가 일반 함수라면 this는 전역객체(window)와 바인딩 된다.
var value=1
const obj={
  value:100,
  foo(){
    console.log(this);//obj .. {value:100, foo:f}
    console.log(this.value);//100

    function bar(){
      console.log(this);//window .. 중첩 함수이기 때문이다
      console.log(this.value);//1 .. 전역 변수 value의 값
    }
  }
}
  • 그러나 .. 중첩 함수, 콜백 함수는 기존의 함수의 기능을 보조하는 역할을 하기 때문에 this가 전역 객체가 아닌 메소드 또는 객체 자체를 가리켜야 하는 경우도 있다.

방법1. this를 특정 변수가 가리키게 만드는 방법이 있다.

var value=1
const obj={
  value:100,
  foo(){
    console.log(this);//obj .. {value:100, foo:f}
    console.log(this.value);//100

    function bar(){
      const that=this;
      console.log(that);// obj .. {value:100,foo:f}
      console.log(thit.value);//100
    }
  }
}

방법2. Function.prototype.apply / call / bind를 사용해 콜백 함수에 명시적으로 this를 바인딩하는 방법

var value=1;
const obj={
  value:100,
  foo(){
    setTimeout(function (){
      console.log(this.value)//100

    }.bind(this),1000)
  }
}

방법3. 화살표 함수를 사용하면 바로 this 바인딩일치 시킬 수 있다.

var value=1;
const obj={
  value:100,
  foo(){
    setTimeout(()=>console.log(this.value),1000)//100
  }
}

메서드 호출

  • 메서드 내부의 this는 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩된다
const person={
  name:'kim',
  getName(){
    return this.name;
  }
}
console.log(person.getName())//'kim'

person 객체의 getName 프로퍼티는 person객체에 포함된 것이 아닌 독립적인 객체이다. 따라서 해당 객체는 경우에 따라 다른 객체의 메소드가 될수도 있고, 일반함수로 호출될 수도 있다.

const anotherPerson={
  name:'park'
}
// 유형1. 다른 객체의 메소드로 할당
anotherPerson.getName=person.getName;
console.log(anotherPerson.getName)// park

// 유형2. 변수에 할당
const p=person.getName;
console.log(p)// ' '
// 전역에서의 this이므로 window.name의 값이 리턴된다
// 브라우저에서 window.name은 built-in 프로퍼티이고, 디폴트가 ''이다
// node.js에서는 undefined이다.

// 유형3. 프로토타입 메서드 내부에 할당
function Person(name){
  this.name=name;
}
Person.prototype.getName=function(){
  return this.name;
}
const me=new Person('kim');
me.getName()//kim

Person.prototype.name='park'
console.log(person.prototype.getName())// park

생성자 함수 호출

생성자 함수 내부의 this는 나중에 생성될 인스턴스가 바인딩된다

function Circle(radius){
  this.radius=radius
  this.getRadius=function(){
    return this.radius;
  }
}

const c1=new Circle(5);
const c2=new Circle(10);

console.log(c1.getRadius);//5
console.log(c2.getRadius);//10

(new연산자와 호출하지 않으면 생성자 함수가 아닌 일반 함수로 동작하여 undefined가 리턴된다)

Function.prototype.apply/call/bind

첫 번째 인수로 전달한 특정 객체를 호출한 함수의 this에 바인딩한다

function getThisBinding(){
    return this;
}
const thisArg={a:1};

console.log(getThisBinding());

console.log(getThisBinding.apply(thisArg));
console.log(getThisBinding.call(thisArg));

bind()는 메서드의 this와 메서드 내부의 중첩함수 또는 콜백함수의 this간 불일치를 해결학 위한 용도로 사용된다.

const person={
  name:'kim',
  foo(callback){
    setTimeout(callback,1000);
  }
}
person.foo(function(){
  console.log(this.name);//해당 함수가 실행될 때의 위치는 함수 밖이기 때문에 일반함수 취급을 한다. 따라서 'kim'이 아닌 'undefined'가 리턴된다.
});

이때 bind()를 사용하면 this가 가리키는 대상을 하나로 묶을 수 있다.

const person={
  name:'kim',
  foo(callback){
    setTimeout(callback.bind(this),1000);//bind의 첫번쨰 인자로 this를 보냈기 때문에 콜백함수 내부와 외부의 this는 같은 대상을 가리킨다
  }
  person.foo(funcion(){
    console.log(this.name)// kim
  })
}
profile
오늘 배운건 오늘 소화하자!

0개의 댓글