자바스크립트

this

데이터_박과장 2023. 11. 16. 09:41

this

javascript에서의 this라는 키워드는 거의 모든 상황에서 객체이며 문법적으로는 '나'와는 단어와 비슷하다. this의 값은 this를 사용하는 해당 함수를 어떻게 실행하느냐에 따라 값(의미)이 바뀐다.

this를 실행하는 방식

this는 크게 4가지 방식으로 실행을 하며 각각의 방식에 따라 가리키는 주체가 달라진다.

1. Regular function call - 일반 함수 실행 방식

1.1 strict mode가 아닌 경우

function foo () {
  console.log(this.name); // 'this' === global object (브라우저상에선 window 객체)
}

foo();

일반 함수 방식이란 위와 같이 일반적으로 함수를 실행하는 가장 기본적인 방식이다. 이 방식에서 this는 global object (브라우저상에선 window 객체)이다.

1.2 strict mode인 경우

'use strict';

var name = 'ken';

function foo () {
  console.log(this.name); // 'this' === undefined
}

foo();

strict mode에서 "this"는 undefined이다.
(개발자가 window를 가르키려고 this를 쓰지는 않기 때문)

1.3 일반 함수 실행 방식 예제

var age = 100;

function foo () {
  var age = 99;
  bar(age);
}

function bar (age) {
  console.log(this.age); // 100
}

foo();

위 함수에서 99가 실행이 될것 같지만 bar()라는 함수가 실행되는 부분에서 일반함수 실행방식으로 실행시켰기때문에 this는 window가 되었고 window.age는 100이기 때문에 100이 실행되었다.

 

2. Dot Notation - 점 방식

오브젝트 메소드 형식으로 실행시키는 방식

 

2.1 Dot Notation 예제

var age = 100;

var ken = {
  age: 35,
  foo: function foo () {
    console.log(this.age); // 35
  }
};

ken.foo();

this함수를 호출할때 함수 앞에 .을 사용하여 메소드를 실행시킬 경우, this는 .앞의 객체가 this의 값으로 설정이 된다.

 

2.2 Dot Notation 예제

function foo () {
  console.log(this.age);
  alert(this.age);
}
var age = 100;
var ken = {
  age: 36,
  foo: foo
};
var wan = {
  age: 32,
  foo: foo
};


foo();
ken.foo(); // 36
wan.foo(); // 32

그냥 foo()를 실행을하게되면 100이 출력되겠지만 dot nation방식으로 실행을 하기 때문에 this가 가리키는 값이 .앞의 객체로 바뀐다.

 

2.3 Dot Notation 예제

var age = 100;
var ken = {
  age: 35,
  foo: function bar () {
    console.log(this.age);
  }
};
var wan = {
  age: 31,
  foo: ken.foo
};
var foo = ken.foo;
ken.foo();  // 35
wan.foo();  // 31
foo(); // what is the value of 'this' in this case?  // 100

ken.foo : ken이라는 객체안의 메소드지만 결국 bar라는 함수이다.
객체안의 메소드지만 this의 방식에 따라 각각 다르게 호출이 된다.

3. Function.prototype.call, Function.prototype.bind, Function.prototype.apply - explicit binding (명시적 바인딩)

call, bind, apply와 같은 메소드들을 사용해서 함수를 실행하는 명시적 바인딩 방법

3.1 Explicit binding 예제

var age = 100;

function foo () {
  console.log(this.age);
  alert(this.age);
}

var ken = {
  age: 35,
  log: foo
};

// foo function gets invoked
// `this` refers to first argument


var kenLog = ken.log;

foo();
kenLog();
foo.call(ken); // ?
foo.apply(ken); // ?

foo.call(wan) : foo()라는 함수가 실행이 되는데 this의 값이 인자의 값으로 준 wan이 되어 실행이 된다.

foo.apply(ken) : foo()라는 함수 실행이 되고 ken이라는 인자값이 this의 값으로 설정이 되어 실행이 된다.

일반함수 실행 방식, dot Notaition 방식과 다르게 this의 값이 어떤 객체가 되어야 하는지 개발자가 직접 정하고 명령을 내릴 수 있다.

 

 

foo, foo.call, ken.log, 그리고 kenLog 함수들이 다르게 동작하는 이유 설명

 

 

foo(); 

이 경우 foo 함수는 전역 컨텍스트에서 호출. 일반적인 함수 호출(foo())에서 this는 전역 객체를 가리킴. 브라우저 환경에서 전역 객체는 window이므로 따라서, 이 경우 this.age는 전역 변수 age (값은 100)을 참조한다.

 


kenLog(); 

여기서 kenLog는 ken.log의 참조를 복사합니다. kenLog()가 호출될 때, 이 함수는 전역 컨텍스트에서 실행. 따라서 this는 다시 전역 객체를 가리키고, this.age는 전역 변수 age (값은 100)를 참조한다.

 


foo.call(ken); 

call 메서드는 함수를 주어진 컨텍스트(ken 객체) 내에서 실행하게 됨. 이 경우 this는 call 메서드의 첫 번째 인자인 ken 객체를 가리키고. 따라서 this.age는 ken 객체의 age 프로퍼티 (값은 35)를 참조한다.

 


foo.apply(ken);

apply 메서드는 call 메서드와 매우 유사하게 작동한다. 차이점은 인자를 배열로 전달한다는 것이다. 이 예제에서는 추가 인자가 없으므로 call과 동일하게 작동한다. 따라서 이 경우에도 this는 ken 객체를 가리키고, this.age는 ken 객체의 age 프로퍼티 (값은 35)를 참조한다.



결론적으로, foo()와 kenLog() 호출은 전역 객체의 age 프로퍼티를 참조하므로 100을 출력하고, foo.call(ken)과 foo.apply(ken) 호출은 ken 객체의 age 프로퍼티를 참조하므로 35를 출력함. 이러한 동작은 JavaScript에서 this 키워드의 값이 함수 호출 방식에 따라 달라지는 것을 보여준다.

 

4. 'new' keyword 방식

4.1 'new' keyword 예제

function Person () {
  console.log(this);
  this.age = 3333;
}

new Person();

this의 값을 판별하기 위해서는 foo라는 함수가 어떻게 실행되느냐를 찾아야한다. new라는 단어를 앞에 넣어 실행을 했다. 이럴 경우, this의 값은 빈 객체가 생성이 된다고 생각하면 된다. 빈 객체가 새롭게 생성돼서 함수속의 this값으로 할당이 되어 함수가 실행이 된다. ( 새로운 객체가 this값으로 들어간다.)

4.2 'new' keyword 예제

function Person () {
  // this = {};

  this.name = 'ken';

  // {
   // name : 'ken';
  // }
  
  // return this;
}

var ken = new Person();
console.log(ken);  // Person?{name: "ken"}

new Person() 하면 this는 새로운 객체가 된다.
Person함수 내부에는 그 빈 객체에 name이라는 key에 ken이라는 값을 할당해준다. Person에는 return이 없지만 new라는 단어를 사용하면 return을 해주지 않았지만 new를 사용하여 함수를 실행하게 되면 사용자가 쓰지 않아도 return this;가 자동으로 된다.

보통 new라는 키워드를 쓸 경우, return을 잘 쓰지 않는다.

 

 

 

new를 통해 객체생성 없이 같은 결과를 출력하려는 경우:

new Person()을 사용하지 않고 동일한 효과를 내려면, Person 함수 내에서 명시적으로 새 객체를 생성하고 반환하는 로직을 작성해야 한다. 생성자 함수 내에서 새 객체를 만들고 그 객체에 속성을 추가한 후, 이 객체를 반환하면 new 키워드 없이도 새 객체를 생성할 수 있다.

 


function Person() {
    var obj = {};
    obj.name = 'ken';
    return obj;
}

var ken = Person();
console.log(ken);  // {name: "ken"}

 

 

이 코드에서 Person 함수는 먼저 빈 객체 obj를 생성한다. 그런 다음 obj에 name 속성을 추가하고, 마지막으로 obj를 반환한다. var ken = Person(); 호출로 인해, ken 변수에는 {name: "ken"}이라는 새 객체가 할당된다.

 

 

4.3 'new' keyword 예제

function Person (name) {
  this.name = name;
  console.log(this);
}

var ken = new Person('ken');
console.log(ken);	// Person {name : 'ken'};

함수기때문에 마찬가지로 인자를 넣을 수 있다.

 

4.4 'new' keyword 예제 : Constructor function (생성자 함수)

function Person (name, age) {
  this.name = name;
  this.age = age;
}

// instances"라고 한다.
var ken = new Person('ken huh', 34);
var wan = new Person('wan huh', 30);

console.log(ken);  // Person?{name: "ken huh", age: 34}
console.log(wan);  // Person?{name: "wan huh", age: 30}

// 새로운 객체가 선택이 된다.

생성자함수는 보통 맨앞을 대문자로 해준다. new를 써서 함수를 실행시킬때마다 this에는 새로운 객체가 할당이 돼서 실행이 된다. 새로 만들어진 객체들은 instance라고 불려진다.

함수 호출되기까지의 과정과 이 4가지 상황을 많이 연습하면 this에 대해 완벽하게 이해할 수 있다.

'자바스크립트' 카테고리의 다른 글

AJAX (Asynchronous Javascript And XML)  (0) 2023.11.16
JSON  (0) 2023.11.16
콜백  (0) 2023.11.16
Closure (클로저)  (0) 2023.11.15
원시타입, 참조타입  (0) 2023.11.15