[TIL] JavaScript에서 this?

승민·2024년 1월 17일
0

TIL

목록 보기
16/20

프로젝트에서 전체 선택 버튼을 구현하던 중, 이벤트 리스너 함수를 일반 함수에서 화살표 함수로 변경하자 동작이 실패했습니다. 다음은 문제 코드입니다

function AllCheck() {
	for (let i = 0; i < $AllCheckBox.length; i++) {
    $AllCheckBox[i].checked = this.checked;
	console.log(this); // 이벤트 리스너의 this는 무조건 변수의 html 값
  }
}

const AllCheck = () => {
	for (let i = 0; i < $AllCheckBox.length; i++) {
    $AllCheckBox[i].checked = this.checked;
	console.log(this);// 화살표 함수는 부모 함수를 this로 가짐, window가 됨
  }
}

$checkAll.addEventListener("change", AllCheck);

일반 함수에서는 this가 이벤트 리스너의 DOM 요소($checkAll)를 가리키지만, 화살표 함수는 정의 시점의 렉시컬 스코프의 this (여기서는 window)를 가리킵니다. window.checked는 undefined이므로 체크박스 상태 반영이 실패했습니다.

화살표 함수에서 event.target을 사용해 DOM 요소를 참조하면 문제를 해결할 수 있습니다.

const AllCheck = (event) => {
	for (let i = 0; i < $AllCheckBox.length; i++) {
    $AllCheckBox[i].checked = event.target.checked;
	console.log(this);
  }
}

$checkAll.addEventListener("change", AllCheck);

this?

JavaScript에서 this는 함수가 호출되거나 정의되는 방식에 따라 동적으로 결정되는 컨텍스트를 가리킵니다.

  1. 일반 함수 호출
    독립적으로 호출된 일반 함수의 this는 전역 객체를 가리킵니다.
    브라우저 -> window, Node.js -> global, Strict mode -> undefined
function sayName() {
  console.log(this.name);
}
sayName(); // '' (window.name)
  1. 메서드 호출
    객체의 메서드로 호출될 때, this는 호출한 객체를 가리킵니다.
    단, 메서드가 화살표 함수인 경우 렉시컬 스코프의 this를 따릅니다.
const obj = {
  name: "lee",
  say() {
    console.log(this.name); // 'lee'
  }
};
obj.say(); // 'lee'
const x = obj.say;
x(); // '' (window.name, 독립 호출)
  1. 화살표 함수
    화살표 함수는 자신만의 this를 가지지 않습니다. 대신, 정의 시점의 렉시컬 스코프의 this를 캡처합니다.
    호출 방식에 상관없이 this는 고정됩니다.
const obj = {
  name: "lee",
  say2: () => {
    console.log(this.name); // '' (window.name)
  }
};
obj.say2(); // '' (렉시컬 스코프: window)
  1. 생성자 함수
    new 연산자로 호출된 생성자 함수에서, this는 새로 생성된 객체를 가리킵니다.
function Human(name) {
  this.name = name;
}
const person = new Human("lee");
console.log(person.name); // 'lee'
  1. 이벤트 리스너
    이벤트 리스너로 등록된 일반 함수에서, this는 이벤트가 바인딩된 DOM 요소를 가리킵니다.
    화살표 함수를 사용하면 this는 렉시컬 스코프의 this를 따릅니다.
header.addEventListener("click", function () {
  console.log(this); // header (DOM 요소)
});

header.addEventListener("click", () => {
  console.log(this); // window (렉시컬 스코프)
});
  1. call, apply, bind
    call(thisArg, arg1, arg2, ...): this를 설정하고 함수를 즉시 호출, 인자를 개별적으로 전달.
    apply(thisArg, [arg1, arg2]): this를 설정하고 함수를 즉시 호출, 인자를 배열로 전달.
    bind(thisArg): this가 설정된 새 함수를 반환, 즉시 호출하지 않음.
function sayName() {
  console.log(this.name);
}
sayName.call({ name: "lee" }); // 'lee'
sayName.apply({ name: "lee" }); // 'lee'
const boundSay = sayName.bind({ name: "lee" });
boundSay(); // 'lee'

this가 변경되는 경우

this는 다음 상황에서 기본값(전역 객체 또는 undefined)과 다르게 설정됩니다:

메서드 호출: obj.method() → this는 obj.
생성자 호출: new Constructor() → this는 새 객체.
이벤트 리스너: 일반 함수 → this는 DOM 요소.
call, apply, bind: this는 지정된 객체.
화살표 함수: this는 정의 시점의 렉시컬 스코프의 this.


const obj = {
  name : "lee",
  say () {
    console.log(this.name); // 'lee'
    function say2 () {
     console.log(this.name); // '', 호출할 때 this를 바꿔주는 행위를 안함
    }
    const say3 = () => {
      console.log(this.name) // 'lee', 화살표 함수는 부모함수의 this를 물려 받는다.
    }
    say2();
    say3(); 
  },
}

const say = obj.say;

obj.say();
say(); // 전부 this가 window에 바인딩, ''만 출력

header.addEventListener('click', () => {
  console.log(this); // header html값
})
// 변수.이벤트 리스너의 this는 무조건  변수의 html 값

정리

일반 함수: 호출 방식에 따라 this 결정 (전역 객체, 객체, DOM 요소 등).
화살표 함수: 정의 시점의 렉시컬 스코프의 this 고정.
call, apply, bind: this를 명시적으로 설정.

0개의 댓글