[JS] this

2022. 8. 6. 22:03학습/JavaScript

반응형

JS this

this

this는 실행 컨텍스트가 생성될 때 결정이 됩니다. 그 뜻은 함수를 호출할 때 결정된다고 할 수 있습니다.
this를 구분하는 방법은 대표적으로 함수메서드 입니다.

전역공간의 this

  • 전역공간의 this는 전역 객체를 가리킵니다.
    • 브라우저 환경: window
    • Node.js 환경: global

전역 변수

전역 변수를 선언하면 JS엔진은 이를 전역객체의 프로퍼티로 할당합니다.
좀더 개념을 확장하면 JS의 모든 변수는 특정객체(LexicalEnvironment)의 프로퍼티로 동작함

그렇다면 var로 선언한 전역변수전역객체의 프로퍼티의 차이는 무엇일까요?

  • 호이스팅
  • configutration 의 True, False

window.a = 1;
var b =2;
delete window.a;
delete b;
console.log(a); //Uncaught ReferenceError: a is not defined
console.log(b); //2
// 'b'는 configuration이 'false'
// 의도치 않게 삭제되는 것을 방지함

함수와 메서드

  • 함수는 그 자체로 독립적인 기능을 수행
  • 메서드는 자신이 호출한 대상 객체에 관한 동작을 수행
    • 메서드는 객체의 메서드로서 호출할 경우에만 메서드로 동작
    • 그렇지 않으면 함수로 동작

함수 호출과 메서드 호출을 구분하는 법은 함수 앞의 점(.)의 유무 입니다.


obj.run();//메서드 호출
run();//함수 호출

상황에 따른 this

1. 메서드의 this

  • this에는 호출한 주체에 대한 정보가 담깁니다.
    • 즉, 점(.) 앞에 있는 객체를 가리킵니다.

2. 함수의 this

  • 함수의 this는 전역객체를 가리킵니다.
  • 메서드 내부의 함수일지라도 함수로서 호출되면 this는 전역 객체를 가리킵니다.

주변환경의 this를 받기 위해선 어떻게 할까요?

  • 변수(self)를 활용해서 this 우회하기

var obj = {
    outer: function () {
      console.log(this); // {outer: ƒ}
      var self = this;
      var inner = function () {
          console.log(self); // {outer: ƒ}
      }
      inner();
    }
}
obj.outer();

3. this를 바인딩하지 않는 화살표 함수

  • ES6에서 '화살표 함수'를 도입하였습니다.
    • 이 함수는 this를 바인딩하지 않습니다.
    • 상위 스코프의 this를 그대로 활용할 수 있습니다.

4. 콜백함수에서의 this

콜백함수는 제어권을 가진 함수에 따라 this의 대상이 다릅니다.

  • 따로 지정하지 않는다면 전역객체를 가리킵니다.
  • addEventListener의 경우 자신의 this를 상속하도록 정의합니다.

document.body.innerHTML += '<button id="a"></button>';
document.body.querySelector('#a')
    .addEventListener('click', function (e) {
        console.log("this:",this,"e:",e)
});

5. 생성자 함수 내부에서의 this

"생성자"는 구체적인 인스턴스를 만들기 위한 일종의 틀입니다.

JS는 new 명령어와 함께 함수를 호출하면 생성자의 역할을 합니다.

  • 생성자함수로 함수가 호출된 경우의 this는 인스턴스 자신이 됩니다.

생성자의 prototype 프로퍼티를 참조하는 __proto__ 프로퍼티를 가지는 인스턴스를 만들고, 공통 속성 및 개성을 해당 객체(this)에 부여합니다.


var Dog = function (name, age) {
    this.type = '포유류';
    this.name = name;
    this.age = age;
};
var terry = new Dog('테리',6);
console.log(terry)

명시적으로 this 바인딩하는 방법

1. call 메서드


Function.prototype.call(thisArg[, arg1[, ...]])

  • 메서드의 호출 주체인 함수를 즉시 실행하도록합니다.
  • 메서드의 첫 번재 인자를 this로 바인딩합니다.
  • 이후 매개변수는 호출할 함수의 매개변수로 합니다.

var func = function(a,b,c) {
    console.log(this,a,b,c);
}
func(1,3,4);//Window {window: Window, self: Window, document: document, name: '', location: Location, …} 1 3 4
func.call({x:1},2,3,4);//{x: 1} 2 3 4

  • 메서드의 함수는 원래 '점(.)' 앞에있는 함수를 this로 받지만 call 메서드는 지정한 객체가 this가 됩니다.

2. apply 메서드


Function.prototype.apply(thisArg[, argsArray])

  • 두 번째 인자를 배열로 받아서 그 배열의 요소들을 호출할 함수의 매개변수로 지정합니다.

var func = function(a,b,c) {
    console.log(this,a,b,c);
}
func(1,3,4);//Window {window: Window, self: Window, document: document, name: '', location: Location, …} 1 3 4
func.apply({x:1},[2,3,4]);//{x: 1} 2 3 4

그럼 call, apply는 언제 사용할까요?

  1. 유사 배열 객체에 배열 메서드 적용
    
    var obj = {
        0:'a',
        1:'b',
        2:'c',
        length:3
    };
    Array.prototype.push.call(obj,'d');
    console.log(obj); // {0: 'a', 1: 'b', 2: 'c', 3: 'd', length: 4}
    var arr = Array.prototype.slice.call(obj);
    console.log(arr); // ['a', 'b', 'c', 'd']
    //얕은 복사만 진행하는데 중첩객체는 그럼??
    
    
    • 유사배열 객체에는 arguments, NodeList 등이 있습니다.
    • 문자열의 경우
      • length 프로퍼티가 읽기 전용이기 때문에 원본 문자열을 변경하는 메서드에는 에러가 나타납니다.
      • concat 역시 제대로 된 결과를 얻지 못합니다.
      
      var str = 'string'
      Array.prototype.push.call(str,'d');
      //Uncaught TypeError: Cannot assign to read only property 'length' of object '[object String]'
      
      
    • 그런데 ES6에서 Array.from을 도입합니다.
      • 유사배열객체 또는 순회 가능한 모든 종류의 데이터를 배열로 만드는 게 가능해졌습니다.
  1. 생성자 내부에서 다른 생성자 호출
  2. 
    function Person(name,age) {
        this.name = name;
        this.age = age;
    }
    
    function Coach(name, age, tech) {
        Person.call(this, name, age); //this는 Coach 인스턴스를 나타냄
        this.tech = tech;
    }
    
    var chulsu = new Coach("철수", 34, "Vue");
    console.log(chulsu);//Coach {name: '철수', age: 34, tech: 'Vue'}
    
    
  1. apply : 여러 인수를 묶어 하나의 배열로 전달하고 싶을 때​
  2. 
      var numbers = [2,3,45,56];
      var max = Math.max.apply(null,numbers);
      console.log(max);
    
      //번외 ES6-전개연산자
      var numbers = [2,3,45,56];
      var max = Math.max(...numbers);
      console.log(max);
    
    

3. Bind


Function.prototype.bind(thisArg[, arg1[, arg2[, ...]])

  • call 처럼 함수를 실행하지는 않고 반환만 진행합니다.
    • 함수에 this를 미리 적용
    • 부분 적용함수를 구현
      • bind를 호출할 때 전달했던 인수들의 뒤에 이어서 등록됨
      
      var func = function (a, b, c, d) {
        console.log(this, a, b, c, d);  
      };
      var Subfunc = func.bind({ x: 1 }, 4, 5);
      Subfunc(6, 7); //{x: 1} 4 5 6 7
      
      
    • bind 메서드가 적용된 함수는 name 프로퍼티에 'bound'가 붙습니다.
    • 
      console.log(Subfunc.name); //bound func
      
      

이 글은 "코어자바스크립트" 내용에 기반하여 작성한 글입니다.

잘못된 부분이나 이해가 잘못된 부분에 대해서는 댓글로 써 주시면 감사하겠습니다!

반응형

'학습 > JavaScript' 카테고리의 다른 글

[JS] 클로저  (0) 2022.08.07
[JS] 콜백함수  (0) 2022.08.07
[JS] 실행 컨텍스트  (0) 2022.07.31
[JS] 원시타입과 참조타입의 차이  (0) 2022.07.16
[JS]자바스크립트란?  (0) 2021.11.18