JS - 함수와 This, Binding
1. 바인딩
프로그램의 어떤 기본 단위가 가질 수 있는 구성 요소의 구체적인 값, 성격을 확정하는 것을 말한다.
let a = 123;
위의 코드는 이름, 자료형, 값에 각각 a
, int
, 123
을 할당했는데 이 과정을 바인딩이라고 한다.
2. this
자바스크립트는 인터프리터에 의해 줄 단위로 해석된다. 인터프리터가 현재 실행되는 환경을 실행 컨텍스트라고 하는데, 내부에서 스택으로 관리된다. 실행 중인 컨텍스트를 this가 가리키게 된다.
즉, JS 함수에서 this는 호출한 방법에 의해 결정된다.
const fuc = {
name: 'dave',
call: function () {
console.log(this);
}
}
fuc.call()
실행 결과를 보면 함수를 직접 호출했고, 그 때 호출한 주체가 fuc
함수이므로 this
는 fuc
가 된다.
const myFuc = fuc.call
myFuc()
위 코드를 보면 myFuc
에 함수만 할당했고, 실행하면 this
가 window
를 가리키는 것을 확인할 수 있다. 이는 함수를 실행한 주체가 브라우저이기 때문이다. (Web에서는 window
가 전역객체이다.)
HTML에서도 똑같은 현상을 볼 수 있다.
<!--생략-->
<body style="background-color: dimgray;">
<button id="btn">this</button>
</body>
<!--생략-->
const btn = document.querySelector("#btn")
btn.addEventListener("click", fuc.call)
버튼을 누르면 call
함수가 호출되어 실행되는데 이때 호출한 주체가 button
이기 때문에 this
는 button
이 된다.
(함수 호출 방식에 따른 정확한 차이를 이해하고 싶다면 참조란에 진하게 처리된 링크를 추천)
3. this 정적 바인딩
JS에서 this
를 직접 바인딩 하고 싶다면 몇 가지 방법이 있다.
3.1 변수에 할당하기
const fuc = {
name: 'lee',
whatName: function () {
console.log('I\'m ' + this.name)
}
}
fuc.whatName()
const callMyName = fuc.whatName
callMyName()
위와 같은 코드를 작성하면 fuc
함수 내부 함수인 whatName
함수의 this
는 window
를 가리키게 된다.this
를 다른 변수에 저장하면 해결할 수 있다.
const obj = {
//(A)
name: "lee",
getName: function () {
console.log(this);
//(B)
const that = this;
setTimeout(function () {]
//(C)
console.log(this);
console.log(that);
});
},
};
obj.getName()
(A)지점에서는 this
가 obj
객체를 가리키고 있다. 이는 객체의 메서드를 직접호출 했을 때인 (B)지점까지 유지가 된다. (C) 지점에 도달했을 때는 내부함수에 해당하는데 이 때부터 this
는 전역 객체를 가리키게 된다. that
이라는 변수를 이용해 this
를 저장했을 때와 그렇지 않을 때의 결과를 보면 확인할 수 있다.
3.2 생성자 함수 이용하기
function Name(name) {
this.name = name;
console.log(this)
}
const Im1 = new Name('lee')
const Im2 = Name('lee')
new 연산자와 생성자 함수를 호출하면
- 빈객체를 생성하고 이 객체에 this 바인딩한다.
- 빈객체는 생성자함수의 prototype 프로퍼티가 가르키는 객체를 자신의 프로토타입 객체로 설정한다.
- 빈 객체에 this를 이용해 프로퍼티, 메소드를 생성해 추가한다.
- 객체를 반환한다.
this외에 다른것을 반환하거나 this를 반환하지 않는 함수는 생성자 함수의 역할을 수행할 수 없다는 것을 알 수 있다.
3.3 apply 메서드
함수의 this
에 thisArg
라는 객체를 바인딩하고 argsArray
라는 배열을 인수로 전달하는 함수이다. 이 때, 객체에 프로퍼티가 없다면 동적으로 추가되어 할당된다.
3.4 call 메서드
apply 메서드와 비슷하지만, 배열로 넘기던 인자가 각각 하나의 인자로 넘어가는 차이점이 있다.
let Name = function (name1, name2) {
this.name1 = name1
this.name2 = name2
}
let lee = {}
let park = {}
Name.apply(lee, ['name1', 'name2'])
console.log(lee)
Name.call(park, 'name1', 'name2')
console.log(park)
3.5 bind 메서드
x = 9;
var module = {
x: 81,
getX: function () {
console.log(this.x);
}
};
module.getX();
var retrieveX = module.getX;
retrieveX();
var boundGetX = retrieveX.bind(module);
boundGetX();
앞의 내용들과 마찬가지로 getX
함수만 변수에 할당해서 실행한 결과 this
가 전역 객체를 가리킨다.
bind
메서드를 이용해 this
가 module
이라는 객체를 가리키도록 하면 객체 내부의 x
를 가져올 수 있다.
bind
메서드는 apply
나call
메서드와 달리 함수를 반환하므로 함수를 호출해줘야 한다.
4. 화살표 함수와 this
화살표 함수는 일반 함수들과 달리 this가 동적으로 바인딩되지 않고, 정적으로 언제나 상위 스코프의 this를 가리킨다(Lexical this)
또한 call, apply, bind 메서드를 사용하여 this를 변경할 수 없다.
function foo() {
return a => console.log(this.a)
}
let obj = {
a: 2
};
let obj2 = {
a: 3
};
let bar = foo.call(obj);
bar.call(obj2); // 2
bar
에 obj1
을 바인딩 한 뒤 obj2
로 변경하려 하지만 화살표 함수의 this
는 항상 상위 스코프를 가리키므로 변경되지 않는다. 이러한 특성 때문에 몇 가지 상황에서는 화살표 함수를 사용할 때 주의를 해야 한다.
4.1 메서드
const sayName = {
name: 'lee',
say: () => {
console.log(`my name is ${this.name}`)
console.log(this)
}
}
sayName.say()
say
함수는 화살표 함수여서 this
가 상위 스코프인 window
를 가리킨다.
const sayName = {
name: 'lee',
}
Object.prototype.say = () => {
console.log(`my name is ${this.name}`)
console.log(this)
}
sayName.say()
메서드를 프로토타입을 활용해서 할당하는 경우도 동일한 문제가 발생한다.
4.2 생성자 함수
const Foo = () => {};
console.log(Foo.hasOwnProperty('prototype')); // false
const foo = new Foo(); // 타입에러
생성자 함수는 prototype
프로퍼티를 가지며 prototype
프로퍼티가 가리키는 프로토타입 객체의 constructor
를 사용한다. 하지만 화살표 함수는 prototype
프로퍼티를 가지고 있지 않다.
4.3 addEventListener 함수의 콜백 함수
화살표 함수로 콜백 함수를 구성하면 this
가 window
를 가리키기 때문에 일반 함수로 콜백 함수를 구성해야 한다.
참조
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this
- https://www.youtube.com/watch?v=PAr92molMHU
- https://medium.com/pocs/%EB%B0%94%EC%9D%B8%EB%94%A9-binding-4a4a2f641b27
- https://velog.io/@danmin20/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-this-%EB%B0%94%EC%9D%B8%EB%94%A9%EC%9D%B4%EB%9E%80
- https://velog.io/@proshy/JS-%EC%83%81%ED%99%A9%EC%97%90-%EB%94%B0%EB%A5%B8-this-%EB%B0%94%EC%9D%B8%EB%94%A9
- https://poiemaweb.com/js-this
- https://poiemaweb.com/es6-arrow-function
- https://hyojin96.tistory.com/entry/%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98-Arrow-Function-%EC%97%90%EC%84%9C%EC%9D%98-this-%EB%B0%94%EC%9D%B8%EB%94%A9
Author And Source
이 문제에 관하여(JS - 함수와 This, Binding), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@main_string/JS-함수와-This-Binding저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)