TIL 0306

Kimaramy·2020년 3월 6일
0

Today I Learned

목록 보기
5/5

자바스크립트는 모든 것을 ‘객체’ 환경으로 이해 해야하며, 변수(함수)가 만들어진 환경의 객체를 잘 보아야 한다.

어떤 변수(함수)가 만들어진 환경이 특정 객체 안이라면, 그 함수는 그 객체의 어떤 key에 대한 value가 될 것이다. 즉, 객체에 바인딩 된 것이며, 그 객체의 메소드인 것이다.

반대로, 어떤 변수(함수)가 만들어진 환경이 전역 객체라면, 전역 객체에 바인딩 된 것이며, this는 window(브라우저 환경) || global(노드 환경)이다.

그래서 어떤 객체가 외부의 함수를 자신의 메소드로 사용하고자 한다면, 그 외부함수를 자신에게 바인딩해주어야 하는데, 다음과 같은 방법이 있다.

외부 함수를 바인딩하는 방법

bind, call, apply 프로토타입 메소드

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

const obj = {};

obj.a = outerFn; // 또는
obj.a = outerFn.bind(obj, ...args); // 전달인자 필요시

obj.a(); // this === obj

실제 코드에 적용한 부분

function printRole(user) {
  console.log(user.role);
}

function transformAsHTML(array) {
  const $ul = document.getElementById('container');
  array.forEach(val => {
    const $li = document.createElement('li');
    const $a = document.createElement('a');
    const $div = document.createElement('div');
    $a.textContent = `${val.firstName} ${val.lastName}`;
    $a.className = 'name';
    // console.log(this); // window
    // $a.onclick = val => printRole(val); // arrow function으로 인한 자동 this 바인딩 문제 (this === window)
    $a.onclick = printRole.bind($a, val); // 디버그한 부분
    $div.textContent = val.age;
    $div.className = 'age';
    $li.appendChild($a);
    $li.appendChild($div);
    $ul.appendChild($li);
  });
}

외부 함수를 바인딩하지 않고 사용하는 방법 (간접 바인딩)

익명 함수의 내부에 외부 함수를 실행

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

const obj = {};

obj.a = function() { outerFn() };
obj.a(); // this === window 이지만 이로인한 버그가 일어나지 않음

이 경우 익명함수가 onclick의 값이 된다. ($a의 메소드가 된다)

실제 코드에 적용한 부분

function printRole(user) {
  console.log(user.role);
}

function transformAsHTML(array) {
  const $ul = document.getElementById('container');
  array.forEach(val => {
    const $li = document.createElement('li');
    const $a = document.createElement('a');
    const $div = document.createElement('div');
    $a.textContent = `${val.firstName} ${val.lastName}`;
    $a.className = 'name';
    // console.log(this); // window
    // $a.onclick = val => printRole(val); // arrow function으로 인한 자동 this 바인딩 문제 (this === window)
    $a.onclick = function() { 
      printRole(val);
    } // 디버그한 부분
    $div.textContent = val.age;
    $div.className = 'age';
    $li.appendChild($a);
    $li.appendChild($div);
    $ul.appendChild($li);
  });
}

주의(ES6 Arrow function 사용시)

ES6 arrow function으로 작성시 자동으로 자신이 생성된 객체의 한 단계 상위 객체에 바인딩된다.

const obj = {
  a: () => { console.log(this); },
  b: function() { console.log(this); },
}

obj.a(); // this === Window
obj.b(); // this === obj

또한 이후 다른 객체에 바인딩 할 수 없다.

const arrowFn = () => { console.log(this); };
const fn = function() { console.log(this); }; 

obj.c = arrowFn;
obj.d = fn;

obj.c(); // this === Window
obj.d(); // this === obj

// 강제 바인딩도 안됨
obj.c = arrowFn.bind(obj);
obj.c(); // this === Window
profile
스타트업에서 Software Engineer로 일하고 있습니다

0개의 댓글