[JAVA SCRIPT] 콜백함수 (1)

차슈·2024년 4월 24일
1

JAVA SCRIPT

목록 보기
19/24
post-thumbnail
post-custom-banner

1. 콜백함수

다른 코드의 인자로 넘겨주는 함수
= 제어권을 넘겨줄테니 알고있는 로직으로 처리해줘
ex) forEach, setTimeout

  • call (부르다) + back (되돌아오다) = 되돌아와서 호출해줘

  • 예를들어,

  1. 알람시계를 세팅하고 꿀잠
  2. 맞춰놓은 시간에 알람소리를 듣고 상쾌하게 일어남
  3. 시계의 알람을 설정하는 함수 = 알람시계 호출
  4. 알람시계가 알아서 내가 맞춰놓은 시간이 되었을때 울림
    ➡️ 제어권: 알람시계 (함수)

    함수/메서드에 인자로 넘겨줌으로써 제어권도 같이 넘겨주는 함수


1-1. 제어권

☝️ 콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대한 제어권을 가짐

var count = 0;

var timer = setInterval(function() {
	console.log(count);
	if(++count > 4) // ++한 count의 값이 4보다 크면
	clearInterval(timer); //timer를 멈춰줘
}, 300); //300: 0.3초 간격으로 이 로직을 반복

위에 처럼 콜백 함수의 제어권을 넘겨받은 코드 setInterval이 언제 콜백함수를 호출할지에 대한 제어권을 가진다.
이 코드는 300, 즉 0.3초라는 시점에 실행하겠다라는 것.

var count = 0;
var cbFunc = function () {
	console.log(count);
	if (++count > 4) clearInterval(timer);
};
var timer = setInterval(cbFunc, 300); 
// 호출시점에 대한 제어권은 setInterval이 가지고 있음 

// 실행 결과
// 0 (0.3sec)
// 1 (0.6sec)
// 2 (0.9sec)
// 3 (1.2sec)
// 4 (1.5sec)

원래 cdFunc()를 수행하면 호출주체제어권은 사용자가 됨
setInterval로 넘겨주면 호출주체제어권 모두 setInterval이 됨


1-2. 인자

map 함수 = 각 배열 요소를 변환하여 새로운 배열을 반환 -> 기존 배열을 변경 X

// map 함수에 의해 새로운 배열을 생성해서 newArr에 담음
var newArr = [10, 20, 30].map(function (currentValue, index) {
	console.log(currentValue, index);
	return currentValue + 5;
});
console.log(newArr);

// -- 실행 결과 --
// 10 0
// 20 1
// 30 2
// [ 15, 25, 35 ]

여기서, function (currentValue, index)에서 인자의 순서를 바꾼다면,

var newArr2 = [10, 20, 30].map(function (index, currentValue) {
	console.log(index, currentValue);
	return currentValue + 5;
});
console.log(newArr2);

// -- 실행 결과 --
// 10 0
// 20 1
// 30 2
// [ 5, 6, 7 ]

//index랑 currentvalue는 사람이 인식할 수 있는거 일뿐, 
//컴퓨터는 index를 current로 current를 index로 
//자리처럼 인식

출력값이 달라지고, 의도하지 않은 값이 나온것을 확인할 수 있다.
왜?

  • index랑 currentvalue는 그냥 사람이 인식할 수 있는것
    컴퓨터는 순서가 바뀐것을 인식하지 못하고 그냥 자리처럼 인식해버림

이렇게,
map에서는 인자의 순서까지도 map에게 제어권이 있다.


1-3. this

this

			< this가 전역객체를 참조하지 않는 예외사항 >

제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조

setTimeout(function() { console.log(this); }, 300); // Window { ... }

[1, 2, 3, 4, 5].forEach(function (x) {
	console.log(this); // Window { ... }
});


document.body.innerHTML += '<button id="a">클릭</button';
document.body.querySelector('#a').addEventListener('click', function(e) {
	console.log(this, e);
});

setTimeout 은 내부에서 콜백 함수를 호출할때, call 메서드의 첫번째 인자에 전역객체를 넘김
-> 콜백함수 내부에서 this는 전역객체를 가리킴

forEach도 콜백함수 뒤에 this를 명시하지 않으면 전역객체를 가리킴

addEventListener은 콜백함수 호출시, call 메서드의 첫번째 인자에 addEventListener 메서드의 this를 그대로 넘겨줌

콜백 함수 내에서 this 키워드를 사용하면, 기대한 대로 작동하지 않을 수가 있다.


Array.prototype.mapaaa = function (callback, thisArg) {
  var mappedArr = [];

  for (var i = 0; i < this.length; i++) {
    // call의 첫 번째 인자는 thisArg가 존재하는 경우는 그 객체, 없으면 전역객체
    // call의 두 번째 인자는 this가 배열일 것(호출의 주체가 배열)이므로,
	// i번째 요소를 넣어서 인자로 전달
    var mappedValue = callback.call(thisArg || global, this[i]);
    mappedArr[i] = mappedValue;
  }
  return mappedArr;
};

const a = [1, 2, 3].mapaaa((item) => {
  return item * 2;
});

console.log(a);

call apply 메서드를 쓰면 해결가능!
첫번째 인자에서 콜백 함수 내부에서 사용될 this를 명시적으로 바인딩 하기 때문에 this에 다른 값이 담길 수 있다


2. 콜백 함수 내부의 this에 다른 값 바인딩

콜백함수는 어떤 객체의 메서드를 전달하더라도. 메서드가 아닌 함수로 호출

var obj1 = {
	name: 'obj1',
	func: function() {
		var self = this; //this 참조!!!
		return function () {
			console.log(self.name);
		};
	}
};

// 단순히 함수만 전달한 것이기 때문에, obj1 객체와는 상관이 없음
var callback = obj1.func(); 
//func대신에 function () {
			//console.log(self.name);를 담은것 
			
setTimeout(callback, 1000);

이 코드에서

var callback = obj1.func(); = var callback = obj1.function () {
									console.log(self.name);

이렇게 되는것과 같다. 하지만, 여기선 제대로된 this를 사용하는 건 아니다!

밑에 코드들을 보자.

// (1)
var obj1 = {
	name: 'obj1',
	func: function() {
		var self = this; //이 부분!
		return function () {
			console.log(self.name);
		};
	}
};

// ---------------------------------

var obj2 = {
	name: 'obj2',
	func: obj1.func
};


var callback2 = obj2.func();


setTimeout(callback2, 1500);

var obj3 = { name: 'obj3' };
var callback3 = obj1.func.call(obj3);
setTimeout(callback3, 2000); //2초
//(2)
var obj1 = {
	name: 'obj1',
	func: function() {
		var self = this; 
		return function () {
			console.log(self.name);
		};
	}
};

// ---------------------------------


var obj2 = {
	name: 'obj2',
	func: function() {
		var self = this; 
		return function () {
			console.log(self.name);
		};
};
  

var callback2 = function () {
	console.log("obj2");


setTimeout(callback2, 1500);


var obj3 = { name: 'obj3' };
var callback3 = obj1.func.call(obj3);
setTimeout(callback3, 2000); //2초

(1)번 코드와 (2)번 코드는 this를 우회적으로 활용한 코드이다.
이게 전통적인 코드이지만, 가장 좋은 방법은 bind 메서드를 사용하는 방법이다.

bind 메서드 활용

var obj1 = {
	name: 'obj1',
	func: function () {
		console.log(this.name);
	}
};
//함수 자체를 obj1에 바인딩
//obj1.func를 실행할 때 무조건 this는 obj1로 고정
setTimeout(obj1.func.bind(obj1), 1000);

var obj2 = { name: 'obj2' };
//함수 자체를 obj2에 바인딩
//obj1.func를 실행할 때 무조건 this는 obj2로 고정
setTimeout(obj1.func.bind(obj2), 1500);

참고

post-custom-banner

0개의 댓글