[JavaScript] this, call, apply, bind
this 따로 지정해주지 않으면 지금의 실행 컨텍스트가 활성화된 객체를 바라본다고 볼 수 있을것같다.
전역 환경에서의 this는 node환경에선 global객체, 브라우저 환경에서는 window객체이다.
함수와 메서드
함수는 전역에서 선언되어 어디서든 호출 가능 함수의 this는 전역 객체
// 호출 방법
함수();
메서드는 자신을 가진 객체를 통해 호출 해야함 메서드의 this는 호출의 주체
// 호출 방법
객체.메서드();
var o1 = {
outer: function() { // this는 o1
console.log(this);
var innerfunc = function() {
console.log(this); // this는 global
}
innerfunc();
var o2 = {
innermethod : innerfunc // this는 o2
}
o2.innermethod();
}
}
o1.outer();
outer도 함수를 참조한 메서드라서 outer에 참조한 함수가 호출될 때 this는 o1인가보다.
직접 호출 할수 있는 innerfunc의 this는 global로 나온다.
innerfunc 함수를 참조한 innermethod의 this는 o2로 나온다.
메서드로 만들지 않은 함수에서도 메서드의 this와 같은 값을 사용하고 싶을 때 내부 스코프에 존재하는 this를 별도의 변수에 할당하여 사용하는 방법이 있다.
var o1 = {
outer: function() {
console.log(this);
var self = this; // o1을 저장해 놓고
var innerfunc = function() {
console.log(this);
console.log(self); // innerfunc에서 o1호출
}
innerfunc();
}
}
o1.outer();
self라는 변수를 만들어 this를 할당 해주면 innerfunc에서도 o1를 사용 할 수 있다.
일반 함수와 화살표 함수의 this
var o1 = {
outer: function() {
console.log(this); // this o1
var innerfunc1 = function() { // 일반 함수
console.log(this); // this global
}
innerfunc1();
var innerfunc2 = () => { // 화살표 함수
console.log(this); // this o1
}
innerfunc2();
}
}
o1.outer();
화살표 함수에서는 this가 함수가 선언된 객체를 바라본다.
화살표 함수는 this를 binding 기능을 이미 하고 있다. binding은 아래에 설명 할 것.
생성자 함수 내부에서의 this
var 변수 = new 함수();
함수안의 this는 변수 object(함수도 object)를 new로 생성해서 할당 하면 this가 알아서 object를 binding 하는 것 같다.
명시적 this binding
call, apply, bind
- call : this를 넘겨주면서 함수를 즉시실행한다.
call을 이용한 명시적 binding
var func = function(a,b,c) {
console.log(this,a,b,c);
}
func(10,20,30); // this는 global
func.call({},50,60,70); // this는 {}
func({},20) 실행시
var obj = {
a : 1,
method : function(num) {
console.log(this.a,num);
}
}
obj.method(2); // this는 obj
obj.method.call({a:10},20); // this는 {a:10}
유사배열객체에서 사용 (배열은아니지만 배열처럼 쓸 수 있는것 key값이 숫자고 length를 가지고 있으면 된다.)
var obj = {
0:'a',
1:'b',
2:'c',
length:3
}
Array.prototype.push.call(obj,'d');
console.log(obj);
var arr = Array.prototype.slice.call(obj);
console.log(arr);
var arr2 = Array.from(obj); // object to array
console.log(arr2);
생성자에서 사용하는 예제
function Person(name, gender) {
this.name = name;
this.gender = gender;
}
function Student(name,gender,school) {
Person.call(this,name,gender);
this.school = school;
}
function Employee(name,gender,company) {
Person.call(this,name,gender);
this.company = company;
}
var sp = Student("ㅁㅁㅁ","m","sky");
var sp = Employee("ㄴㄴㄴ","m","sam");
- apply
사용법은 call과 같다 다만 매개변수를 배열로 묶어서 참조해줘야 한다. apply도 즉시실행
var func = function(a,b,c) {
console.log(this,a,b,c);
}
func(10,20,30); // this는 global
func.apply({},[50,60,70]); // this는 {}
결과는 위의 call을 사용했을 때와 같음.
사용예제
var numbers = [10,20,30,40];
var max = Math.max(...numbers);
console.log(max);
var max2 = Math.max.apply(null,numbers);
console.log(max);
- bind : 즉시 실행하지 않음, this를 미리 적용해 놓음
var func = function(a,b,c,d) {
console.log(this,a,b,c,d);
}
func(1,2,3,4); // global
// bind로 미리 적용 해 놓기
var bindFunc = func.bind({});
bindFunc(5,6,7,8); // {}
// bind로 부분 적용해 놓기
var bindFunc2 = func.bind({},9,10);
bindFunc2(7,8); // {}
// bind된 함수인지 알수 있다.
// name 프로퍼티
console.log(func.name);
console.log(bindFunc.name);
console.log(bindFunc2.name);
응용
위의 self를 이용하여 this를 사용한 예제를 call을 이용하여 수정
var o1 = {
outer: function() {
console.log(this);
var innerfunc = function() {
console.log(this);
}
innerfunc.call(this); // <------
}
}
o1.outer();
this가 o1이 된 것을 확인 할 수 있다.
bind를 사용하여 수정
var o1 = {
outer: function() {
console.log(this);
var innerfunc = function() {
console.log(this);
}.bind(this) // <------
innerfunc();
}
}
o1.outer();
결과는 같다.