프론트엔드 개발일지 #13-Javascript ( 콜백함수 1 -콜백함수 개념, 제어권, this바인딩, 객체의 메서드 전달시 this)

조아라·2024년 10월 12일
0
post-thumbnail

콜백함수

다른 코드의 인자로 넘겨주는 함수. '넘겨준다'는 말은 콜백 함수를 넘겨받는 코드도 있다는 얘기이다. (예를들어 forEhch,setTimeout등) 콜백함수에서 넘겨받은 코드들은 콜백함수를 필요에 따라서 적절한 시점에 실행하게 된다. (제어권 = 넘겨 받은 코드)

  • 제어권
  1. 콜백 함수 호출 시점
    제어권을 넘겨받은 코드는 콜백 함수 호출 시점에대해 제어권을 갖는다.
var count = 0;

// timer : 콜백 내부에서 사용할 수 있는 '어떤 게 돌고있는지'
// 알려주는 id값
var timer = setInterval(function() {
	console.log(count);
	if(++count > 4) clearInterval(timer);
}, 300);

var count = 0;
var cbFunc = function () {
	console.log(count);
	if (++count > 4) clearInterval(timer);
};
var timer = setInterval(cbFunc, 300);

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

콜백 함수를 넘겨받은 setIntervals가 언제 콜백함수를 호출할지 제어권을 갖고 있다.
0.3초(300)라는 적절한 시점을 함수에 적어놓은대로 실행을 한다.

==> 원래 cbFunc()을 수행한다며 호출주체와 제어권은 사용자가 되지만,
setInterval(cbFunc,300);으로 넘겨주게되면 호출주체는 모두 setIntervals가 된다.

  • 인자

map함수는 각 배열 요소를 반환하여 새로운 배열을 반환한다. 기존 배열을 변경하지않고 새로운 배열을 생성하는데,

// 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)이 안에 변수 순서를 바꾼다면 자동으로 인식이 될 지 확인 해 봤다.

// map 함수에 의해 새로운 배열을 생성해서 newArr에 담고 있네요!
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 ]

결과는 변수의 순서를 바꾼게 인식이 되지않아서 currentValueindex로 인식하고 인덱스에 +5한 결과가 반환 되었다.

==> 이처럼 map 메서드를 호출해서 원하는 배열을 얻고자 한다면 규칙대로 작성해야한다.
콜백 함수를 넘겨받은 코드에게 제어권이 있기때문에 인자의 순서까지도 넘겨받은 코드에게 제어권이 있다.

  • this

    콜백함수도 함수이기때문에 기본적으로 this는 전역객체를 참조한다. 하지만 제어권을 넘겨받은 코드에서 콜백함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조한다.

    이걸 내부적으로 어떻게 가능하게 하는지, map함수를 구현해 본 코드가 있다.

    // Array.prototype.map을 직접 구현해봤어요!
    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를 명시적으로 binding하기 때문에 this에 값이 담겼다.

그렇다면 이 코드를 이해 할 수 있다.
```javascript
//이젠 이 코드를 좀 더 잘 이해할 수 있어요!!

// setTimeout은 내부에서 콜백 함수를 호출할 때, call 메서드의 첫 번째 인자에
// 전역객체를 넘겨요
// 따라서 콜백 함수 내부에서의 this가 전역객체를 가리켜요
setTimeout(function() { console.log(this); }, 300); // Window { ... }

// forEach도 마찬가지로, 콜백 뒷 부분에 this를 명시해주지 않으면 전역객체를 넘겨요!
// 만약 명시한다면 해당 객체를 넘기긴 해요!
[1, 2, 3, 4, 5].forEach(function (x) {
	console.log(this); // Window { ... }
});

//addEventListener는 내부에서 콜백 함수를 호출할 때, call 메서드의 첫 번째
//인자에 addEventListener메서드의 this를 그대로 넘겨주도록 정의돼 있어요(상속)
document.body.innerHTML += '<button id="a">클릭</button';
document.body.querySelector('#a').addEventListener('click', function(e) {
	console.log(this, e);
});

콜백함수는 함수다

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

var obj = {
	vals: [1, 2, 3],
	logValues: function(v, i) {
		console.log(this, v, i);
	}
};

//method로써 호출
obj.logValues(1, 2);

//callback => obj를 this로 하는 메서드를 그대로 전달한게 아니에요
//단지, obj.logValues가 가리키는 함수만 전달한거에요(obj 객체와는 연관이 없습니다)
[4, 5, 6].forEach(obj.logValues);

profile
끄적 끄적 배운 걸 적습니다 / FRONT-END STUDY VELOG

0개의 댓글