this

하태현·2020년 11월 12일
0

javascript

목록 보기
9/23
post-thumbnail

"this" keyword

자바스크립트에서 this키워드는 항상 함수 내부에서 사용된다. this값은 this가 사용된 함수가 어떤 방식으로 실행 되었는지에 따라 결정된다.

var name = "킹스맨";
var hth = {
  name: "하태현",
  logName: function () {
    console.log(this.name);
  }
};
var func = hth.logName;
hth.logName(); // "하태현"
func();	// "킹스맨"

함수 선언시에는 this값을 판별할 수 없다.
this값을 알기 위해선 함수 실행문을 찾고, 어떻게 실행되었는지만 알면 this값을 판별할 수 없다.

함수 실행 방법

  1. Regular Function Call
  2. Dot Notation(Object Method Call)
  3. Call, Apply, Bind
  4. "new" Keyword

위 4가지 실행방법에 따라 this값이 판별된다.

1. Regular Function Call

this는 함수가 "어떻게" 실행되느냐에 따라 결정되기 때문에 함수 실행 방식이 중요하다.

var name = "킹스맨";
function log () {
  console.log(this.name);
}
func();	// "킹스맨"

func()와 같이 함수이름 만으로 실행하는 경우 일반함수 호출이라고 한다.

일반 함수 호출 방식에서 this값은 Global Object(브라우저에선 window 객체)

var name = "킹스맨";
var hth = {
  name: "하태현",
  logName: function () {
    console.log(this.name);
  }
};
var func = hth.logName;
func();	// "킹스맨"

this가 사용된 함수는 hth라는 객체의 logName이라는 속성으로 할당되어있다.
그러나 함수의 선언이나 할당은 this값과 무관하다.
위 예제 코드에서는 함수 실행 부분이 func()로 일반 함수 호출 방식으로 실행되었기 때문에 this값은 Global Object이다.

var name = "킹스맨";
function foo () {
  var name = "하태현";
  bar();
}
function bar () {
  console.log(this.name);
}
foo(); // "킹스맨"

bar함수에서 this가 사용되었고 barfoo함수 내부에서 일반 함수 호출 방식으로 실행되어서 이때 this값은 Global Object이다.

var name = "킹스맨";
var hth = {
  name: "하태현",
  printName: function () {
    foo();
  }
};
function foo () {
    console.log(this.name);
  }
hth.printName(); // "킹스맨"

printName은 Dot Notation을 이용해 실행되었지만 this가 사용된 foo는 일반 함수 호출 방식으로 실행되어 this는 Global Object이다.

2. Dot Notation

var name = "킹스맨";
var hth = {
  name: "하태현",
  logName: function () {
    console.log(this.name);
  }
};
var func = hth.logName;
// Dot Notation
hth.logName();
// Regulat Function Call
func();

여기서 hth.logName()func()는 같은 함수를 실행한다. 그러나 실행방식의 차이로 this값이 달라진다.
Dot Notation을 이용해 함수를 실행하면, 해당함수 내부의 thisDot 앞의 객체를 가리킨다. hth.logName()에서 thishth객체를 가리킨다.

var age = 20;
function logAge () {
  console.log(this.age);
}
var hth = {
  age: 28,
  logAge: logAge
};
var htg = {
  age: 26,
  logAge: hth.logAge
};
hth.logAge(); // 28
htg.logAge(); // 26
console.log(hth.logAge);
console.log(htg.logAge);


console.log의 결과를 보면 둘다 같은 함수를 가리킨다. 결국 hth.logAge(), htg.logAge()를 실행하면 this값은 Dot앞의 객체인 hthhtg를 가리키게 되어 결과 값이 28, 26이 나온다.

function makePerson(name, age) {
  return {
    name: name,
    age: age,
    verifyAge: () => {
      return this.age > 21;
    }
  };
}
const hth = makePerson("hth", 28);
if(hth.verifyAge()){
  console.log("Yes Beer");
} else {
  console.log("No Beer");
}

결과는 "No Beer"가 나온다.
예상대로라면 28살이기 때문에 "Yes Beer"가 나와야 하는데...
verifyAge를 자세히 보면 화살표 함수가 쓰였다.
찾아보니 일반함수의 this값은 동적으로 결정 되는데, 화살표 함수는 항상 상위 스코프의 this값을 가리키게 되어있다고 한다.
그래서hth.verifyAge()를 실행하면 hth객체의 상위 스코프인 Global Object가 this값으로 결정되어 this.ageundefined가 된다.

3. Call, Apply, Bind

우선 자바스크립트의 객체(배열, 함수)는 내장된 메소드를 가지고 있다. 여기서 설명할 함수 실행 방식은 함수(function)가 갖고 있는 특정 메소드를 이용한 방법이다.

명시적 바인딩(Explicit Binding)

Call, Apply, Bind는 명시적 바인딩을 할때 사용하는 함수이다.
어떤 함수안에서 사용되는 this의 값이 어떤 값이 사용되야하는지 명확할때 사용하는 방식

Function.prototyope.call

모든 함수는 .call메소드를 사용할수 있다.

function logName () {
  console.log(this.name);
}
const person = {
  name: "하태현",
};
// call 메소드를 이용한 함수 실행
logName.call(person);	// "하태현"
  1. call메소드의 역할은 logName함수의 this값을 person으로 설정한다.
  2. logName함수를 실행(logName()으로 실행하는 것과 같은 의미)
function foo (a, b, c) {
  console.log(this.age + a + b + c);
}
const hth = {
  age: 28,
};
foo.call(hth, 1, 2, 3); // 34

.call메소드의 첫번째 인자는 this값으로 사용되고, 두번째 인자부터 해당함수의 인자로 사용된다.

  • .call메소드는 받을 수 있는 인자 개수는 제한이 없다.

Function.prototyope.apply

function foo (a, b, c) {
  console.log(this.age, a + b + c);
}
const hth = {
  age: 28,
};
foo.apply(hth, [1, 2, 3]); // 34

.call메소드와 다른게 뭘까??
.apply메소드는 2개의 인자만을 받는다.
첫번째 인자는 this값으로 사용되고, 두번째 인자는 무조건 배열 이여야 하고 그 배열의 요소들이 함수의 인자로 전달된다.

.call.apply

공통점

  • 첫번째 인자는 this값으로 설정
  • 메소드가 사용된 함수를 실행

차이점

  • call : 첫번째 인자를 제외한 나머지를 모두 .call이 사용된 함수의 인자로 전달(인자 개수 제한 없음)
  • apply : 두번째 인자로 배열을 받을수 있고, 해당 배열의 모든 요소들을 함수의 인자로 전달(2개의 인자만 받는다)

Function.prototyope.bind

function foo () {
  console.log("hello");
}
// bar 변수에는 새로운 함수가 담긴다.
const bar = foo.bind();
bar();

.bind메소드는 함수를 실행하지 않고 새로운 함수를 반환한다.

function logName () {
  console.log(this.name);
}
const person = {
  name: "하태현",
};
const bar = foo.bind(hth);
bar(); // "하태현"

barthis값을 hth로 설정한 foo함수이다.

function foo (a, b, c) {
  console.log(this.age + a + b + c);
}
const hth = {
  age: 28,
};
const bar = foo.bind(hth, 1, 2, 3);
bar(); // 34

bind메소드는 call메소드와 유사하게 인자 개수에 제한이 없고, 위 예제 코드에서는 this값과 인자값을 저장한 새로운 함수를 만든다.

  • bind메소드는 새로운 함수를 반환하고, 그 함수를 실행해야 원본 함수가 실행된다.

4. "new" Keyword

Keyword(키워드)는 자바스크립트에 내장된 명령어이다.

function foo () {
  console.log("function");
}
new foo();

기본적으로new 키워드와 함께 함수를 실행하면 일반 함수 실행문과 동일한 작동을 한다.

function foo () {
  console.log(this);
}
new foo(); // 빈 객체 출력
function Person (name) {
  this.name = name;
  console.log(this);
}
new Person("hth");

필요한 경우 새로운 속성을 추가 할수 있다.

  • new키워드와 함께 사용될 경우 해당 함수를 생성자 함수라고 부른다.
function Person (name) {
  this.name = name;
  console.log(this);
}
Person("hth"); // 일반함수로 사용
new Person("hth"); // 생성자 함수로 사용

보통 일반 함수 용도로 만든 함수는 일반함수로만 사용하고, 생성자함수 용도로 만든 함수는 생성자 함수로만 사용한다.

function Person (name, age) {
  this.name = name;
  this.age = age;
}
new Person("hth", 28); 

생성자 함수는 통상적으로 함수명을 대문자로 시작한다.

profile
왜?를 생각하며 개발하기, 다양한 프로젝트를 경험하는 것 또한 중요하지만 내가 사용하는 기술이 어떤 배경과 이유에서 만들어진 건지, 코드를 작성할 때에도 이게 최선의 방법인지를 끊임없이 질문하고 고민하자. 이 과정은 앞으로 개발자로 커리어를 쌓아 나갈 때 중요한 발판이 될 것이다.

0개의 댓글