본문 바로가기
FRONTEND/Javascript

[Javascript] This 정리

by LAY CODER 2021. 5. 2.

This

 

Javascript에서 '나 자신' 이라는 뜻이다.

 

어떤 상황인지에 따라서 '나 자신'은 계속해서 바뀌고 This가 무엇인지에 따라서 의미(값)도 바뀐다.

 

 

var myName = 'window name';

function log() {
    console.log(this.myName);
}

var obj = {
    myName: 'jasn',
    logName: log,
};

log(); // undefined
obj.logName(); // jasn

 

 

바닐라코딩 영상을 보면서 this를 정리해봤는데

 

처음부터 막힌 부분은 vscode에서 node를 이용해서 출력해보니

 

log(); 를 실행했을 때 'window name'이 아니라 계속 undefined가 나오는 것이었다.

 

이유를 찾아보니 node와 웹에서 전역 범위에 접근하는 건 서로 다른 구문이 필요하다는 것이다.

 

웹에서는 window, self, frames 등을 사용할 수 있지만

 

node.js 에서는 global을 사용해야 한다.

 

그래서 이 두 글로벌 객체의 명칭을 globalThis로 통일했다고 한다.

 

위 구문을 이용 하려면 크롬에서는 window, globalThis를 이용해야 하고

 

node에서는 global과 globalThis 를 이용해야한다.

 

아직까지 양쪽에서 window, global을 각각 지원하는 이유는 호환성 때문에 없애지 못한 것이다.

 

 

globalThis.myName = 'window name';

function log() {
    console.log(this.myName);
}

var obj = {
    myName: 'jasn',
    logName: log,
};

log(); // window name
obj.logName(); // jasn

 

 

node에서 다시 출력이 잘 되는 걸 확인할 수 있다.

 


 

 

일반 함수 실행 방식에서 this

 

 

stric mode가 아닐 때 foo(); 와 같이 일반 함수 실행 방식으로 this를 출력해보면

 

this는 global객체(브라우저에서는 윈도우)를 가르킨다.

 

 

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

foo();

// ========================= 출력값 ==============================

/* 
<ref *1> Object [global] {
  global: [Circular *1],
  clearInterval: [Function: clearInterval],
  clearTimeout: [Function: clearTimeout],
  setInterval: [Function: setInterval],
  setTimeout: [Function: setTimeout] {
    [Symbol(nodejs.util.promisify.custom)]: [Function (anonymous)]
  },
  queueMicrotask: [Function: queueMicrotask],
  clearImmediate: [Function: clearImmediate],
  setImmediate: [Function: setImmediate] {
    [Symbol(nodejs.util.promisify.custom)]: [Function (anonymous)]
  }
}
*/

 

 

strict mode에서는 undefined이 출력되는 걸 확인할 수 있다.

 

 

'use strict';

function foo() {
    console.log(this); // stric mode에서 this는 undefined
}

foo(); // undefined

 

 

함수에서 일반 함수 실행 방식으로 this를 불러도 this는 global(window) 객체가 된다.

 

 

globalThis.age = 100;

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

function bar() {
    console.log(this.age); // 100
    // 'use strict' 을 쓰면 age가 정의되지 않았다고 error가 뜬다.
}

foo();

 


 

Dot Notation(점 방식)에서 this

 

Dot Notation(점 방식)에서 this는 점 앞에 있는 객체를 나타낸다.

 

globalThis.age = 100;

let jasn = {
    age: 31,
    foo: function bar() {
        console.log(this.age);
    },
};

let ken = {
    age: 35,
    foo: jasn.foo,
};

let foo = jasn.foo;

jasn.foo(); // 31 (점으로 불렀을 때 this는 점 앞의 객체)
ken.foo(); // 35 (점으로 불렀을 때 this는 점 앞의 객체)
foo(); // 100 (일반함수 방식일 때 this는 윈도우)

 


 

 

Function.prototype.call, Function.prototype.bind, Function.prototype.apply

 

위 3가지는 this값을 직접적으로 지정해주는 방식으로

 

이 때 this는 function의 인자 값(지정한 객체) 가 된다.

 

 

globalThis.age = 100;

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

let ken = {
    age: 35,
};

let jasn = {
    age: 31,
};

foo(); // 100
foo.call(ken); // 35
foo.apply(jasn); // 31

 

 

인자가 여러개인 경우에는 첫 번째 인자가 되는 객체가 this가 되고

 

나머지는 arguments가 된다.

 

 

globalThis.age = 100;

function foo(a, b, c, d, e) {
    console.log(this.age);
    console.log(arguments);
}

let jasn = {
    age: 31,
};

// call은 인자의 수가 정해져 있지 않다.
// 첫 번째 인자 : this , 나머지 : arguments
foo.call(jasn, 1, 2, 3, 4, 5); // 31 , [Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }

// apply는 인자를 두 개만 받는다.
// 첫 번째 인자 : this , 두 번째 인자 : 무조건 배열(배열의 요소들이 arguments)
foo.apply(jasn, [1, 2, 3, 4, 5]); // 31, [Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }

 

 

bind는 바로 함수를 실행하지 않고 인자로 받은 객체를 this로 설정하고 함수를 반환한다.

 

일반 함수실행 방식으로 해당 함수를 실행 해보면 인자로 받은 객체가 this가 된 것을 확인할 수 있다.

 

 

globalThis.age = 100;

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

let jasn = {
    age: 31,
};

// bind는 바로 함수를 실행하지 않는다. 인자로 받은 객체를 this로 설정하고 함수를 반환
// 첫 번째 인자 : this
let bar = foo.bind(jasn);
// 함수를 실행
bar(1, 2, 3, 4, 5); // 31, [Arguments] { '0': 1, '1': 2, '2': 3, '3': 4, '4': 5 }

 


 

'new' 키워드에서 this

 

new를 사용하여 함수를 호출할 때 this를 찍어보면

 

새로 생성되서 할당 된 새로운 객체가 찍히는 걸 확인할 수 있다.

 

 

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

// new : 새로운 객체가 생성되서 실행된다.
new foo(); // foo{}

 

 

new를 이용해서 함수를 생성하면 비어있는 this 객체가 할당되고

 

속성을 지정해주면 객체에 속성이 들어간 채로 this 객체를 반환하게 된다.

 

 

function foo() {
    // new로 생성하면 주석 부분이 자동으로 된다고 생각하면 된다.

    // this = {};

    this.name = 'jasn';

    // {
    //     name: 'jasn'
    // }

    // return this;
}

// new : 새로운 객체가 생성되서 실행된다.
let jasn = new foo(); // foo{}
console.log(jasn); // foo { name: 'jasn' }

 

 

아래와 같이 객체를 생성할 때 인자를 넘겨서 속성을 지정해줄 수도 있다.

 

 

function foo(name) {
    // new로 생성하면 주석 부분이 자동으로 된다고 생각하면 된다.

    // this = {};

    this.name = name;

    // {
    //     name: 'jasn'
    // }

    // return this;
}

// new : 새로운 객체가 생성되서 실행된다.
let jasn = new foo('jasn'); // foo{}
console.log(jasn); // foo { name: 'jasn' }

 

 

new를 써서 만드는 함수를 보통 생성자 함수라고 하고

 

생성자 함수의 첫 글자는 보통 대문자로 작성한다.

 

이 때, 만들어진 객체를 인스턴스(instance) 라고 부른다.

 

 

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

// new는 별개의 새로운 객체를 생성
// 새로 만들어진 객체를 인스턴스(instance) 라고 부른다
let jasn = new Person('jasn', 31);
let ken = new Person('ken', 34);
console.log(jasn); // Person { name: 'jasn', age: 31 }
console.log(ken); // Person { name: 'ken', age: 34 }

 

 

Reference


www.youtube.com/watch?v=ayyuU0xdbIU&t=71s

developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/globalThis

댓글