[JS] this 바인딩

AREUM·2022년 10월 23일
0

Javascript이론

목록 보기
3/10
post-thumbnail

this 공부하면서 제일 정의되어있지 않아서 공부하는데 나로써 이해하는지 굉장히 힘들었다.
이해는 했다고 생각했지만, 막상 설명하려고 하면 어떻게 설명을 해야하는 지가 어려움을 느꼈다.
내가 이해한 this를 토대로 정리해서 글로 남겨보려고 한다.

this란

👉🏻 객체지향 언어에서는 클래스로 생성한 인스턴스 객체를 의미하고, 클래스에서만 사용할 수 있기 때문에 혼란스럽지 않지만, 자바스크립트에서의 this는 상황에 따라 this가 바라보는 대상이 달라진다.

this를 공부하기전에는 전역공간에서 전역변수를 선언하면 당연히 알아서 자동으로 전역객체 를 바라보는거 아니야? 라고 생각했는데

여기서 깨달은 점은 전역변수를 선언하면 전역공간에서 호출을 했기때문에 전역객체의 프로퍼티로 할당한다라는 것이다.

여기서 조금 더 말을 정리 해보면
❗️자바스크립트의 this는 선언이 아니라 어디에서 호출하느냐에 따라 this가 결정된다는 것을 알게 되었다.

조금 더 나아가서는 ❗️어디서 어떻게 호출을 했느냐에 따라 this가 결정❗️된다.

객체의 프로퍼티: 자바스크립트의 모든 변수는 특정객체의 프로퍼티로서 동작하기 때문이다.
특정객체는 실행컨텍스트의 렉시컬환경을 말한다.

❗️렉시컬환경은 JavaScript 코드에서 변수나 함수 등의 식별자를 정의하는데 사용하는 객체이다.


자 이제 여러상황에서 this가 어디를 바라보는지를 보자.
첫번째로,

1. 전역공간에서의 this

예시를 보며 이해해보자.

var a = 1;

console.log(a);
console.log(window.a);
console.log(this.a);

이렇게 작성하게 된다면, console.log에서 무엇을 보여줄건가 ?

전역공간에서 a로 변수를 선언을 해주었을 뿐인데 모두 '1'을 보여준다.

앞에서 this를 설명할때 선언이 아니라 호출시점이다.
전역공간에서 this를 console.log를 호출 시켜줬기 때문에 a라는 객체를 프로퍼티가 할당되었을 것이다.


여기를 보면 이해가 갈거다.
전역공간인 window에 a라는 객체프로퍼티가 생성이 되었다.


두번째의 상황은,

2. 함수에서의 호출

var afunc = function(x){
  console.log(this, x);
}
func(1);

function afunc2() {
  console.log(this);
}
func2();

function afunc3() {
  console.log(this);
  function afunc3_1() {
    console.log(this);
  }
  afunc3_1();
}
afunc3();


console.log를 보면 this는 전역함수든, 내부함수든 전역객체에 바인딩 되는걸 볼 수 있다.
어? 그럼 메소드 내에서 함수나 콜백함수는 다르지 않을까 ? 한번 해보자.

var obj = {
  amothod: function () {
    console.log('amothod', this);
    function func4 () {
      console.log('func4', this);
    }
    func4();
  }
}
obj.amothod();

var obj2 = {
  amothod: function () {
    setTimeout(function() {
      console.log('obj2', this);
    }, 1000)
  }
}
obj2.amothod();

정말 함수에서 this는 어디서든 관계없이 전역객체를 바인딩 하는 걸 볼 수 있다.

2-1. 우회법 : 함수내부에서 this가 전역객체를 바라보는 걸 방지하는 방법

this의 값을 지정해주는 방법이다.
한번 해 보자.

var obj = {
  amothod: function () {
    console.log('amothod', this);
    
    var self = this;
    
    function func4 () {
      console.log('func4', self);
    }
    func4();
  }
}
obj.amothod();

var obj2 = {
  amothod: function () {
    
    var self = this;
    setTimeout(function() {
      console.log('obj2', this);
    }, 1000)
  }
}
obj2.amothod();


엇 ? 메소드에서의 내부함수에서는 전역객체를 바라보진 않지만 콜백함수에서는 this가 전역객체를 바라본다.
여기서 콜백함수에서는 this값을 지정 해주는 것이 무시 되는것을 알 수 있다.

콜백함수의 전역객체를 바인딩 되는 것을 어떻게 막을 수 있을 까 ?

this를 바인딩 하지 않는 함수

ES6에서부터 함수 내부에서 this가 전역객체를 바라보는 문제를 보완한다고 this를 바인딩하지 않는 화살표 함수를 새로 도입했다고 한다.
ES5 환경에서는 사용하지 못한다고 한다.
( ES5환경에서는 막을 수 있는 방법인 뒤에 나올 call, apply, bind 메소드를 사용하지 않고 ES6에서는 간결하고 편리한 화살표함수를 사용한다고 한다. )

👉🏻 화살표 함수는 스코프체인상 제일 가까운 this에 접근한다.❗️

그럼 화살표 함수를 사용해 보자 !

var obj = {
  amothod: function () {
    console.log('amothod', this);
    var func4 = () => {
      console.log('func4', this);
    }
    func4();
  }
}
obj.amothod();

var obj2 = {
  amothod: function () {
    setTimeout(() => {
      console.log('obj2', this);
    }, 1000)
  }
}
obj2.amothod();

this가 전역객체를 바라보지 않는 것을 볼 수 있다.

2-2. 잠깐의 번외편 : 일반함수 vs 화살표 함수.

일반함수호출위치에 따라 this 정의
화살표함수자신이 선언된 함수 범위에서 this 정의 ( 즉, 상위 스코프의 this를 가르킨다. )

const user = {
  name: 'yang',
  normal: function() {
    console.log(this.name);	// yang
  },
  arrow: () => {
    console.log(this.name);	// undefind
  }
}
user.normal();
user.arrow();

첫번째 콘솔은 yang, 두번째 콘솔에는 undefind가 나온다.

❓ 왜 why
👉🏻 익명함수인 normal라는 메소드 안에 함수를 선언했고 그 안에서 호출을 했기 때문에 user라는 객체 안에서 name을 찾게 되지만,
arrow는 자신이 선언되어있는 함수범위에서 this를 찾기 때문에 undefind가 뜬것이다.
( 즉, 화살표함수는 스코프와도 연관이 있다. 결론은 화살표함수에서의 this는 상위스코프를 가르킨다. )

또 다른 예제를 보자.
이 경우에는 어떻게 출력이 될까 ?

const timer = {
  name: 'yang',
  timeout: function () {
    setTimeout(function() {
      console.log(this.name);
    }, 2000);
  }
}
timer.timeout()

const timer2 = {
  name: 'yang',
  timeout: function () {
    setTimeout(() => {
      console.log(this.name);
    }, 4000)
  }
}
timer2.timeout()

첫번째 timer는 undefind가 뜨고, 두번째 thimer2는 상위스코프인 yang이라는 것이 뜬다.

3. 메서드로서 호출

앞서, 전역공간에서의 this에서 설명 했듯이 자바스크립트에선 객체의 프로퍼티에 함수를 할당한다고 했다.

❗️객체 지향 프로그래밍
객체를 사용하여 개체를 표현하는 방식을 객체 지향 프로그래밍(object-oriented programming, OOP) 이라 부릅니다.

메서드 만들기.

user = {
  name: yang,
  age: 30,
  pr: function() {
  	console.log('안녕하세요');
  }
}
user.name();

user라는 객체를 만들었고 그 안에 name, age를 메서드로 사용할 수 있고, 함수를 만들고 그 함수를 메서드로도 사용 할 수 있다.

user(객체:능력).name(메소드:행동)();
메서드(행동)는 this로 객체(능력)를 참조한다.

동일하지만 단축한 코드이다. function은 생략이 된다.

user = {
  greet: function() {
    alert("Hello");
  }
};

// 단축 구문
user = {
  greet() {
    alert("Hello");
  }
};

function을 생략해도 메서드를 정의할 수 있다.

메서드 호출

자 그럼 객체에 접근하기 위해 메서드를 사용해보자.

var user = {
  name: yang,
  age: 30,
  pr: function() {
  	console.log(`안녕하세요', ${user.name} 입니다.`);
  }
}

newuser.name();

그렇다면 호출되는 값은 안녕하세요, yang 입니다. 가 잘 나올 것이다.

흠, 그럼 이런경우는 값이 과연 어떻게 나올까 ?

var user = {
  name: yang,
  age: 30,
  pr: function() {
  	console.log(`안녕하세요', ${user.name} 입니다.`);
  }
}

var newuser = user;
user = null;

newuser.name();

과연 console.log는 무엇을 보여줄까 ?

usernewuser로 다른 하나의 변수를 이용해 객체를 생성 해주었고, usernull로 덮어 씌었고, 호출했다.
그랬더니 에러가 발생한다. 😭
( 이 부분이 이해가 되지 않는다면 데이터할당, 불변값, 가변값 등을 공부하고 와야한다. 그럼 그 뒤의 생성자 호출도 이해가 될 것이다. 비슷한 부분이 엮여있는 맥락이기 때문에 ... )

해결방법은 콘솔의 user.namethis.name로 바꿔주면 된다.

여기서 객체자리에 this를 사용하는 이유를 알 수 있다.
this를 사용하지 않고 외부 변수를 참조해 객체에 접근하는 것도 가능하지만 ! 이러한 경우때문에, user.name대신 this.name을 사용하는 이유이다.

메서드 내부에 this를 이용해 객체에 접근할 수 있다.


또 다른 예시.
이벤트 핸들러안에서의 this는 무엇인가 ?

var btn = document.querySelector('#btn')
btn.addEventListener('click', function () {
  console.log(this);
});

출력되는 값은 btn이 된다.
👉🏻 메서드명의 점(.) 앞부분이 곧 this가된다.


메소드, 함수 호출방법 구분 법

앞 예제들을 이해하고 여기까지 내려왔다면, 함수로서, 메서드로서의 호출방법이 다르다는 것을 눈치를 챘을 것이다.

/* 함수로서 호출 */
var func = function(x) {
  console.log(this, x);
};
func(1);	// Window

/* 메서드로서 호출 */
var obj = {
  method: func 
};
obj.method(2);	// {method: f} 2

함수 앞에 점(.) 이 있는지 여부만으로 간단하게 구분할 수 있다.

메서드로서 호출 : 점 표기법, 대괄호 표기법

var obj = {
  method: function(x) {
  	console.log(this, x);
  }
  inner: {
	methodAA: function() {
    	console.log(this);
    }
  }
};
obj.method(1);	// {method: f, inner{...} } 1
obj['method'](2);	// {method: f, inner{...} } 2

obj.inner.methodAA();	// {methodAA: f}
obj.inner['methodAA']();	// {methodAA: f}
obj['inner'].methodAA();	// {methodAA: f}
obj['inner']['methodAA']();	// {methodAA: f}

이 예시를 보면 차이점을 한 번에 알 수 있다.
대괄호 표기법이든 점 표기법이든 결국, 어떤 함수를 호출할 때 그 함수이름(프로퍼티) 앞에 객체가 명시 되어있는 경우에는 메서드로 호출한 것을...
( 그 객체가 this가 된다는 점 )

4. 생성자 함수 호출

자바스크립트에서의 생성자 함수 는 무엇인가 ?
생성한다. 객체를 생성한다. 새로운 객체를 생성한다.

예를 들어 설명해 보자면, 기본샘플종이서류가(생성자 객체) 있다. 그런데 새로운 이름을 판 도장(새로운 객체안의 내용 new)으로 서류종이에 찍는다. 그럼 새로 판 도장으로 찍은 서류종이(new 생성자함수)라고 설명을 할 것 같다.

사용하는 방법은
기존 함수에 new 연산자를 붙여서 호출하면 해당 함수는 생성자 함수로 동작한다.

변수를 만들어 new 연산자를 사용해 생성자 함수를 만드는데, 변수의 이름을 인스턴스라고 한다.

코드의 예시를 들어보자.

var Dog = function(name, age) {
  	this.breed = 'Shih Tzu';
	this.name = name;
    this.age = age;
};

var choco = new Dog('초코', 5);
var nabi = new Dog('나비', 9);

console.log(choco, nabi);	//choco, nabi를 인스턴스라 부른다.

출력값은

하핳.. ! 보이는 것 처럼 새로운 객체를 생성했다.

그렇다면 new를 붙이지 않는다면 어떤 결과를 보여줄까 ?

var Dog = function(name, age) {
  	this.breed = 'Shih Tzu';
	this.name = name;
    this.age = age;
};

var choco = Dog('초코', 5);
var nabi = new Dog('나비', 9);

console.log(choco, nabi);


결국 '초코'는 undefind의 값을 출력해 버렸다.

❓ 왜 why
일반함수와, 생성자 함수는 함수 호출 시 this바인딩하는 방식이 다르기 때문이다.
일반함수는 호출을 할 시 this는 전역객체에 바인딩 되지만, new 연산자를 사용한 생성자 함수를 호출하면은 this는 생성자 함수가 암묵적으로 생성한 빈 객체에 바인딩된다.

❗️주의할 점은
객체 생성 목적으로 작성한 생성자 함수를 new 없이 호출하거나 일반함수에 new를 붙여 호출하면 오류가 발생한다. 이 점을 주의하자 !

❗️개발자들의 서로 암묵적으로 생성자함수를 알아볼 수 있도록 규칙이 있는데 첫번째 알파벳을 대문자를 사용한다고 한다.


번외 : 객체 리터럴 방식 vs 생성자 함수 방식 차이

// 객체 리터럴 방식
var foo = {
  name: 'foo',
  gender: 'male'
}

console.dir(foo);

// 생성자 함수 방식
function Person(name, gender) {
  this.name = name;
  this.gender = gender;
}

var me  = new Person('Lee', 'male');
console.dir(me);

var you = new Person('Kim', 'female');
console.dir(you);

이 둘의 차이점은
프로토타입 객체( Prototype )에 있다.
이 부분은 나중에 정리가 되면 올려보겠다.

객체 리터럴 방식의 경우, 생성된 객체의 프로토타입 객체는 Object.prototype이다.
생성자 함수 방식의 경우, 생성된 객체의 프로토타입 객체는 Person.prototype이다.

객체 리터럴은 Object.prototype 이지만, 생성자 함수 방식은 생성자 함수의 이름이 지정되어있는 Person.prototype이라는 것이므로 어느 점이 다른지 대충 눈치를 챘다.

5. 명시적인 this 바인딩 call, apply, bind

함수를 즉시실행 하도록 하기 위해 메서드를 이용해서 this를 명시해주고 바인딩을 해줄 수 있는 방법이다.
즉, 인자(arg)this로 만들어 주는 기능이다.

5-1. call메서드와 apply메서드

/* call */
Function.prototype.call(thisArg[, arg1[, arg2[, ...]]])

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

callapply기능적으로는 완전 동일한 역할을 한다.

첫 번째 인자를 this를 넣어주어 바인딩한다.

둘의 차이점
call메서드는 두번째 인자를 매개변수로 지정한다.
반면에, apply메서드는 두 번째 인자를 배열로 받는다는 점이다.

apply는 두 번째 인자를 배열로 받고 그 배열의 요소들을 호출할 함수의 매개변수로 지정한다.


일단 글보단 코드로 비교 해보자.
/* call */
var func = function(a, b, c) {
	console.log(this, a, b, c);
}
func(1, 2, 3);	// window{...} 1 2 3
func.call({ x: 1 }, 4, 5, 6);	// { x: 1 } 4 5 6

var obj = {
	a: 1,
  	mothod: function(x, y) {
    	console.log(this.a, x, y);
    }
}
obj.method(2, 3);	// 1 2 3
obj.method.call({ a: 4}, 5, 6};	// 4 5 6
                
/* apply */
var func = function(a, b, c) {
	console.log(this, a, b, c);
}
func.apply({ x: 1 }, [4, 5, 6]);	// { x: 1 } 4 5 6

var obj = {
	a: 1,
  	mothod: function(x, y) {
    	console.log(this.a, x, y);
    }
}
obj.method.apply({ a: 4}, [5, 6]};	// 4 5 6

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', 4: 'd', length: 4 }

var arr = Array.prototype.slice.call(obj);
console.log(arr);	// [ 'a', 'b', 'c', 'd' ]

여기서 잠깐❗️
객체에는 배열 메서드를 직접 사용할 수 없다.
하지만, 키가 0 또는 양의 정수인 프로퍼티가 존재하고 length 프로퍼티의 값이 0 또는 양의 정수인 객체, 즉 배열의 구조와 유사한 객체의 경우를 유사배열객체라 한다. 그러므로 call, apply메서드를 사용할 수 있다.

👉🏻 slice 메서드
위에 예제에서 원래는 시작인덱스값과 마지막 인덱스값을 받아 시작값부터 마지막값의 앞부분까지의 배열 요소를 추출하는 메서드이다. ( 오직 배열 형태로 복사하기 위해 사용 )
하지만, 매개변수를 아무것도 넘기지 않을 경우에는 그냥 원본 배열의 얕은 복사본을 반환한다.

결국은 call메서드를 이용해 obj를 얕은 복사를 한것인데 slice메서드가 배열 메서드이기 때문에 복사본은 배열로 반환하게 된것이다.


활용편 2. 문자열에 배열 메서드 적용하기.

문자열에서의 배열 메서드는 결론을 먼저 이야기하자면,
결국 에러가 뜨거나 모두 제대로된 출력값을 얻지 못할 것이다.

문자열의 경우는 프로퍼티가 읽기전용이기에 원본 문자열에 변경을 가 하는 메서드는 에러를 던지며, concat처럼 대상이 반드시 배열이여야 하는 경우는 에러가 나지 않지만 제대로 된 결과를 얻을 수없다.
( 메서드는 push, pop, shift, unshift, splice등.. 이 있다. )

이 코드를 하나씩 콘솔에 찍어보면 확인이 된다.

var start = 'hello,';

Array.prototype.push.call(start, ', javascript');
Array.prototype.concat.call(start, ', javascript');
Array.prototype.every.call(start, function(char) {
  return char !== '';
});
Array.prototype.some.call(start, function(char) {
  return char !== '';
});

var mapmethod = Array.prototype.map.call(start, function(char) {
  return char + '!';
});

console.log(mapmethod);

var reducemapmethod = Array.prototype.reduce.apply(start, [
  function(string, char, i) {
    return string + char + i;
  }, ''
])
console.log(reducemapmethod);

ES6에 추가 된 from

유사배열객체 또는 순회 가능한 모든 종류의 데이터 타입을 배열로 전환하는 메서드이다.

var name = 'hello, yang';
var arr = Array.from(name);
console.log(arr);


활용편 3. 생성자 내부에서 다른 생성자 호출

생성자 내부에 공통된 내용이 있을 경우 call, apply메서드를 이용하면 간결한 코드로 반복을 줄일 수 가 있다.

function AnimalType(name, age) {
	this.name = name;
    this.age = age;
};
function Dog(name, age, type) {
 	AnimalType.call(this, name, age);
  	this.type = type;
}
function Cat(name, age, color) {
 	AnimalType.apply(this, [name, age]);
  	this.color = color;
}

var dogtype = new Dog('초코', 5, 'bulldog');
var cattype = new Cat('나비', 9, 'white');

console.log(dogtype, cattype);


5-2. bind 메서드

bind메서드는 ES5에서 추가된 기능이라고 한다.

call과 비슷하지만 다른 점은 즉시 호출하지 않고 넘겨받은 this, 인수들을 바탕으로 새로운 함수를 반환하기만 해주는 메서드라고한다.
쉽게 이야기 한다면, ❗️새로운 인수를 넘기면 기존 bind메서드를 호출할 때, 전달 했던 인수들을 가지고 오고 새로운 인수도 가지고 오게 된다.
👉🏻 함수에 this를 미리 적용하는것부분 적용함수를 구현하는 두가지 목적을 모두 가졌다.

활용편 1. this 지정과 부분 적용 함수.

예시를 보면 조금 더 빠르게 이해가 될 것이다.

var func = function(a, b, c, d) {
 console.log(this, a, b, c, d); 
};
func(1, 2, 3, 4);

var bindFunc1 = func.bind({ x:1 });
bindFunc1(5, 6, 7, 8);

var bindFunc2 = func.bind({ x:1 }, 4, 5);
bindFUnc2(6, 7);
bindFUnc2(8, 9);

첫 번째 func는 전역에 콘솔이 찍힐 것이다.
bindFunc1을 호출 했을 때는 functhis{ x:1 }로 새로운 함수가 담기며, 호출한 5, 6, 7, 8이 호출될 것이다.

그럼 bindFunc2
첫번째 호출했을 때는 { x:1 }, 4, 5로 새로운 함수가 담길 것이고, { x:1 }, 4, 5, 6, 7
두번째 호출 값은 { x:1 }, 4, 5, 8, 9가 호출 되는 것을 볼 수 가 있다.

활용편 2. 콜백, 내부함수에 this전달

/* call */
var objCall = {
 outer: function() {
 	console.log(this);
   	
   	var innerFunc = function() {
    	console.log(this);
    }
    innerFunc.call(this);
 }
}
objCall.outer();

/* bind */
var objBind = {
 outer: function() {
 	console.log(this);
   	
   	var innerFunc = function() {
    	console.log(this);
    }.bind(this);
    innerFunc()
 }
}
objBind.outer();

/* 내부함수에 this 전달 */
var objThis = {
	logThis: functionn() {
		console.log(this);
	},
    logThisLater1: function() {
      setTimeout(this.logThis, 500);
    },
    logThisLater2: function() {
      setTimeout(this.logThis.bind(this), 1000);
    }
}
objThis.logThisLater1();	// window
objThis.logThisLater2();	// objThis { logThis: f, ... }

잠시 위쪽에 우회법으로 화살표함수를 소개했었다.
ES5에서는 call, apply, bind를 적용하였지만, ES6에서 부턴 이런경우 화살표함수를 사용하므로 적용할 필요가 없어 더욱 간결해졌다.

/* call, bind */
var objCallback = {
 outer: function() {
 	console.log(this);
   	
   	var innerFunc = () => {
      console.log(this);
    }
    innerFunc();
 }
}
objCallback.outer();

/* 내부함수에 this 전달*/
var objThis = {
	logThis: function() {
    	console.log(this);
    },
  	logThisLater: function() {
    	setTimeout(() => {
        	console.log(this);
        }, 1500);
    }
}
objThis();

콜백함수와 함께 thisArg를 인자로 받는 메서드

Array.prototype.메서드(callback[, thisArg]);
Array.prototype.from(arrayLike[, callback[, thisArg]]);
Set.prototype.forEach(callback[, thisArg]);
Map.prototype.forEach(callback[, thisArg]);

forEach, map, filter, some, every, find, findIndex, flatMap, from, Set, Map


번외 : 화살표 함수를 사용하면 안되는 경우

이 부분을 이해한다면 잠깐의 번외 편에서 일반함수 vs 화살표함수 예시를 이해했다는 것😘

1. Object 내부의 함쑤로 메소드를 정의하는 경우

const cat = {
  name: 'hodu',
  sayHi: () => console.log(`Hi ${this.name}`)
};

cat.sayHi();	// Hi undefind

메소드를 호출한 객체를 가르키지 않고 상위 컨택스트인 전역객체 window를 가르킨다.
❗️ 즉, 화살표함수로 메소드를 정의하는 것은 좋지 않다.

2. Prototype

const cat = {
	name: 'hodu', 
};

Object.prototype.sayHi = () => console.log(`Hi ${this.name}`);

cat.sayHi()		// Hi undefind

1번과 동일한 이유이다.
❗️ 일반함수로 정의하여 매핑하는것이 일반적이다.

3. 생성자 함수

const Fun = () => {};

/* 화살표함수는 prototype 프로퍼티가 없다. */
console.log(Fun.hassOwnProperty('prototype'));	// false

const fun = new Fun();	// TypeError: Fun is not a constructor

화살표함수는 생성자 함수로 사용할 수 없다.
❓이유는
1. 생성자 함수는 prototype 프로퍼티를 가진다.
2. prototype 프로퍼티가 가르키는 프로토타입 객체의 constructor를 사용한다.
3. ㅠㅠ그런데 화살표함수는 prototype프로퍼티를 가지고 있지 않기 때문에 생성자 함수로 화살표함수를 이용할 수 없다.

4. addEventListener 함수의 콜백함수

화살표함수

const button = document.getElementById('button');

button.addEventListener('click', () => {
  	console.log(this === window);	// true
  	the.innerHTML = 'Clicked button';
});

addEventListener 함수의 콜백 함수를 화살표 함수로 정의하면 this상위 컨택스트인 전역 객체 window를 가리킵니다.

일반함수

const button = document.getElementById('button');

button.addEventListener('click', function() {
  	console.log(this === button);	// true
  	the.innerHTML = 'Clicked button';
});

그러므로 addEventListener함수의 콜백함수 내에서 this를 사용하는 경우,
function키워드로 정의한 일반함수를 사용해야한다.

일반 함수로 정의된 addEventListener 함수의 콜백 함수 내부의 this는 이벤트 리스너에 바인딩된 요소(currentTarget)를 가리킵니다.
( 즉, 저 buttonthis라는 것 )

This를 마무리 지으며..

이 정도면 this를 어느정도 이해 했다고 생각한다.
물론, 공부하다 보면 알고 있어도 잠시 잊어버릴 수도 있지만, 기본적인 기초는 머리에 넣고 이해 했으니 되었다.
그리고 화살표함수를 왜 사용하는지를 알게되었다.
또 !
this를 공부하면서 classprototype과도 연관이 이어져있다는 것을 알게 되었다.
class는 .. 객체지향이다.
공부할 게 아직 많고 멀고 멀었다..

profile
어깨빵으로 부딪혀보는 개발끄적이는 양씨 인간

0개의 댓글