JavaScript This

seul06·2022년 1월 14일
0

JavaScript

목록 보기
25/25
post-thumbnail

✍️ This에 대해서 알아보기 전에 먼저 체크하기 ▼

전역객체(Global Object)

자바스크립트에서 모든 객체는 기본적으로 전역객체의 프로퍼티이다.

  • 모든 객체의 유일한 최상위 객체를 의미하며 일반적으로 Browser-side에서는 window , Server-side(Node.js)에서는 global 객체를 의미한다.

  • 그러므로 글로벌 객체의 이름은 호스트 환경에 따라서 그 이름이 달라질 순 있지만, 공통적으로 ECMAScript에서 정의한 global API들을 모두 가지고 있다.

const o = {'func':function(){
    console.log('Hello world!');
}}
o.func();
window.o.func();
  • func();window.func(); 는 모두 실행이 된다. 모든 전역변수와 함수는 window 객체의 프로퍼티다. 객체를 명시하지 않으면 암시적으로 window의 프로퍼티로 간주된다.



📌 This란?

this 는 '자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수'이다. this 를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메소드를 참조할 수 있다.

  • This는 함수 내에서 함수 호출 맥락(context)을 의미한다. 즉 어떠한 의미가 고정되어 있지 않고, 사용하는 상황에 따라서 가변적일 수 있다.

  • 자바스크립트의 this는 함수 호출 방식에 의해 동적으로 결정된다.

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

  • ✍️ 바인딩 : this의 호출 방식에 따라 this가 특정 '객체'에 연결되는 것



❓ 그렇다면 this의 값은 어떻게 변화할까?
→ 우리는 this 바인딩을 통해 this가 어떤 값과 연결되는지 확인할 수 있다.

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

1. 일반 함수 호출시의 this

일반 함수 방식이란 일반적으로 함수를 실행하는 가장 기본적인 방식이다.

1-1. this와 전역객체

// ex. 1)
a = 5;
console.log(window.a);  // 5


var g = 'Global variable';
console.log(g);  // Global variable
console.log(window.g);  // Global variable
// ex. 2)
function a(){
  return this;
}
a() === window;  // true


function foo() {
  console.log('hello');
}
window.foo();  // 'hello'
  • 기본적으로 this는 전역객체(Global object)에 바인딩된다.

function a() {
  console.log(this);  // window
  function b() {
    console.log(this); // window
  }
  b();
}
a();
  • 전역함수는 물론이고 심지어 내부함수의 경우도 this는 외부함수가 아닌 전역객체에 바인딩된다.
  • 내부함수는 일반 함수, 메소드, 콜백함수 어디에서 선언되었든 this는 전역객체를 바인딩한다.


1-2. strict mode

(1) strict mode가 아닌 경우

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

(2) strict mode인 경우

'use strict';

var name = 'kim';

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

foo();
  • strict mode에서 thisundefined 이다. (개발자가 window를 가르키려고 this를 쓰지는 않기 때문이라고 한다.)




2. 메소드 호출시의 this

메소드 내부의 this는 해당 메소드를 소유한 객체, 즉 해당 메소드를 호출한 객체에 바인딩된다.

var obj1 = {
  name : 'seul',
  greething: function(){
 	 console.log("hello " + this.name);
  }
}

var obj2 = {
  name: 'lee'
}

obj2.greething = obj1.greething;

obj1.greething(); // "hello seul"
obj2.greething(); // "hello lee"




3. 생성자 함수 호출시의 this

  • 자바스크립트의 생성자 함수는 객체를 생성하는 역할을 하며, 기존 함수에 new 연산자를 붙여서 호출하면 해당 함수는 생성자 함수로 동작한다.
  • 생성자내에서 this는 생성자가 만든 객체를 지칭한다.
  • 일반 함수를 호출하면 this는 전역객체에 바인딩되지만 new 연산자와 함께 생성자 함수를 호출하면 this는 생성자 함수가 암묵적으로 생성한 빈 객체에 바인딩된다.

📌 생성자 함수 동작 방식 ▼

1) 빈 객체 생성 및 this 바인딩

  • 생성자 함수의 코드가 실행되기 '전' 빈 객체가 생성되고 이 빈 객체가 생성자 함수가 새로 생성하는 객체이며, 이후 생성자 함수 내에서 사용되는 this는 이 빈 객체를 가리킨다.

2) this를 통한 프로퍼티 생성

  • 생성된 빈 객체에 this를 사용하여 동적으로 프로퍼티나 메소드를 생성할 수 있다. this는 새로 생성된 객체를 가리키므로 this를 통해 생성한 프로퍼티와 메소드는 새로 생성된 객체에 추가된다.

3) 생성된 객체 반환

  • 반환문이 없는 경우, this에 바인딩된 새로 생성한 객체가 반환된다. 명시적으로 this를 반환하여도 결과는 같다.

// ex. 1)
function Person(name){
  this.name = name;
}

const me = new Person('suel');
console.log(me); // { name: "suel" }
// ex. 2)
function Person(){
  this.name ='seul',
  this.age = '20',
  this.f = function(){
    console.log("hello " +this.name)
  }
}

const person1 = new Person();
console.log(person1.name); // seul
console.log(person1.age); // 20
console.log(person1.f()); // hello seul
// ex. 3)
function Person () {
  // this = {};

  this.name = 'kim';
  // {
   // name : 'kim';
  // }
  
  // return this;
}

var kim = new Person();
console.log(kim);  // { name: "kim" }
  • ex.3) new Person() 하면 this는 새로운 객체가 된다.
    Person함수 내부에는 그 빈 객체에 name이라는 key에 kim이라는 값을 할당해준다. Person에는 return이 없지만, new라는 단어를 사용하면 return을 해주지 않았지만 new를 사용하여 함수를 실행하게 되면 사용자가 쓰지 않아도 return this;가 자동으로 된다.
    보통 new라는 키워드를 쓸 경우, return을 잘 쓰지 않는다. / 참고한 글




4. call / apply / bind 호출시의 this

자바스크립트 엔진에 의해 this에 바인딩될 객체는 암묵적으로 함수 호출 패턴에 의해 결정된다. 이외에 this를 특정 객체에 명시적으로 바인딩하는 방법도 있는데, 이를 가능하게 하는 것이 Function.prototype.apply, Function.prototype.call 메소드이다.
이 메소드들은 모든 함수 객체의 프로토타입 객체인 Function.prototype 객체의 메소드이다.

🤔 callapply메소드는 기본적으로 함수를 호출하는 역할을 한다. 기존 함수 호출과의 차이점은? → 해당 메소드를 사용해서 함수를 실행하면 함수의 첫 번째 인자로 전달하는 객체에 this를 바인딩 할 수 있다.

4-1. call

func.call(thisArg[, arg1[, arg2[, ...]]]
  • call을 사용하면 함수를 실행하고 함수의 첫 번째 인자로 전달하는 값에 this를 바인딩 한다.
function person(a,b,c){
  console.log(this.name);
  console.log(a + b + c);
}

const p1 = {
  name: 'kim'
};

person.call(p1, 1,2,3); 
// kim
// 6

4-2. apply

func.apply(thisArg, [argsArray])
  • apply를 사용하면 함수를 실행하고 함수의 첫 번째 인자로 전달하는 값에 this를 바인딩 한다.
  • call과의 차이점은 인자를 배열의 형태로 전달한다는 것이다. 이때, 인자로 배열 자체가 전달하는 것이 아니라 배열의 요소들이 값으로 전달된다.
function person(a,b,c){
  console.log(this.name);
  console.log(a + b + c);
}

const p1 = {
  name: 'kim'
};

person.apply(p1, [1,2,3]); 
// kim
// 6

4-3. bind

func.bind(thisArg[, arg1[, arg2[, ...]]])
  • 첫 번째 인자에 this를 바인딩 한다는 점은 같지만, 함수를 실행하지 않으며 새로운 함수를 반환한다.
  • 반환된 새로운 함수를 실행해야 원본 함수가 실행된다.
function person(a,b,c){
  console.log(this.name);
  console.log(a + b + c);
}

const p1 = {
  name: 'kim'
};

const personName = person.bind(p1, 1,2); 
personName(5); 
// kim
// 8

✍️ 이렇게 this는 기본적으로 window 이지만(strict모드에서는 undefined), 객체 메소드, call & apply & bind, new일 때 this가 어떻게 바뀌는지 유의해야겠다. (이벤트리스너나 화살표함수에서의 this 또한 바뀔 수 있다고 하는데 이 부분도 알아봐야겠다.🤔)

✍️ apply와 call을 알아보면서 이전에 알아보았던 Array.from이 생각났다. 배열과 유사배열을 구분해야 하는 이유로써 유사배열의 경우 배열의 메서드를 쓸 수 없다는 것인데, 이때 call이나 apply를 사용해서 배열 프로토타입에서 forEach와 같은 배열메서드를 빌려오면 된다고 한다.
그리고 그러한 기능을 최신 자바스크립트에서는 이전에 궁금했던 [Array.from] 으로 더 간단하게 된다는 것이었다.
+) []로 감싸져 있다고 다 같은 배열이 아니라는 것, Array.isArray로 판별하는 법, 배열 프로토타입에서 메서드를 빌려쓰는 방법등에 대해서도 이해해야 겠다.




reference
MDN-this
MDN-call
MDN-apply
oneroomtable
poiemaweb
z-call,apply,bind

profile
공부하기

0개의 댓글