TIL_20 / 21일차

minjun kim·2024년 10월 16일
0

콜백함수_기본 1

다른 코드의 '인자'로 넘겨주는 함수는 => 콜백함수
콜백함수 때문에 생기는 여러가지 특징이 있고,
그 특징 때문에 생기는 바람직하지 않는 상황이 있음.

콜백지옥 === 말 그대로 지옥

그래서 이런 것들을 다루기 위해서는
반드시 동기 , 비동기의 개념을 학습해야 한다.

이 비동기적인 것 때문에 발생하는 문제들 때문에
우리는 비동기적인 것을 동기적인 것으로 보이게 만들어야 한다.

우리가 넘겨준 콜백함수를 받은 주체가 된다.
그 콜백함수를 넘겨받은 주체 forEachsetTimeou
필요에 따라 적절한 시점에 실행된다 => 제어권이 그들에게 있다.

알림시계로 콜백함수 예를 들자면
우리가 알람을 울리지 않고 시계가 제어권이 있기 때문에 울려준다.

즉 콜백함수는? 되돌아와서 호출해줘! === call + back
다시 말하면, 제어권을 넘겨줄테니 너가 알고 있는 그 로직으로 처리해줘!

setTimeout 안에 1초후 라는 로직이 있는데
안에 콘솔이 있었지만 setTimeout의 자체의 1초후를 알아서 처리해줌

forEach 도 반복하는 로직을 알아서 반복해서 처리한 것

즉 콜백 함수는 다른 코드 (함수 또는 메서드) 에게 인자로 넘겨줌으로써
그 제어권도 함께 위임한 함수. 자체적으로 내부 로직에 의해
이 콜백 함수를 적절한 시점에 실행한다.


콜백함수_제어권(1)

var count = 0;

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

여기서 timer에 담아서 사용하는 이유는
setInterval에는 timer라는 속성이 있는데
이 변수에 담기면서 그 속성도 옮겨 담김
그래서 clearIntervaltimer로 지정해서 사용할 수 있음

  • 만약에 속성이 담기지 않는다면 undefined가 뜰 것.

++count가 찍히니까 5가 된순간 4보다 커지니까
clearInterval을 사용하면서 이 로직을 빠져나오게 된 것이다.

이렇게 되면서 이 호출 시점에 대한 제어권을 가지게 된거다.
0.3초에 대한 setInterval이 제어권을 가지고 있다는 것이다.
매게변수는 정확히

function(){
    console.log(count);
    if (++count > 4)  clearInterval(timer); 
}

이 부분 까지이기 때문에 넘겨준 함수가 저기까지니까
그럼 이 매게변수를 이제 변수에 담고,

만약 직접 호출하게 된다면?
그럼 1번만 실행되고 멈춰버리게 된다.

cbFunc();
호출 주체가 우리가 되기 때문에 이 호출 시점에 대한
제어권을 우리가 가지고 있는 것이여서,

var timer = setInterval(cbFunc, 300);
이렇게 매개변수로 넣어주면 이 콜백함수의 대한 제어권이 우리에게 없고
제어권이 setInterval 함수에 있기 때문에 결과가 달라진다.

콜백함수_제어권(2)

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

console.log(newArr);

currentValue는 배열안의 인자 값
index는 배열 번호이다.
마찬가지로 배열을 순회하는 콜백함수인 map 함수다.

그렇다면 아래 console.log(newArr)은 무슨 값이 나올까?

undefiend 3개가 나오는데
return문이 없으면 map함수는 무엇인가를 할당하긴 해야된다 배열 크기 만큼
할게 없어서 undefined라도 할당한 것.

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

이렇게 인자값을 모두 +5 해서 return한다는 뜻이고
바깥의 콘솔로 확인하면 15 25 35가 할당된 것을 확인할 수 있다.

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

이렇게 되면? 바깥 콘솔에서 5,6,7로 나오는데
현재 + 5가 index로 인식한 쌔한 느낌이 든다.

// index : 사람이 이해할 수 있는 변수명일 뿐
// currentValue : 사람이 이해할 수 있는 변수명일 뿐

즉 컴퓨터가 인식할 수 있는건 매개변수가 어디에 있는지 몇번째에 있는지
자릿수로 인식할 수 있다.

지금처럼 순서가 바뀌면 index 자리를 currentValue로 인식하고 ,
currentValueindex로 인식한다.

그러니까 아래처럼 return문을 보면
index + 5로 컴퓨터는 읽은것이다.

컴퓨터는 사람이 아니라 이런 시멘틱한 요소들을 이해할 수 없습니다.
항상 기억해야 하는게 mapmap처럼 사용하기 위해서는
원하는 것을 얻고자 한다면 정해진 규칙을 지키면서 사용해야 한다.
(MDN의 사용방법대로 사용해야 함)

사람이 아무리 이 인자를 제어하려해도 할 수 없다.
제어가 가능한건 이 map이라는 함수 만이
콜백함수에 대한 인자의 제어권을 가지고 있는 것이다.


콜백함수_this 바인딩

함수() / Object.메서드()

this 콜백 함수도 함수이기 때문에 기본적으로 this가 전역객체를 참조한다

메서드는 호출주체가 명확하기에 Object를 보지만
함수는 명확하지 않기에 전역객체를 참조한다.

하지만 예외사항이 있다.

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

  1. 호출 시점에 대한 제어권
  2. 인재에 대한 제어권

콜백함수_객체의 메서드 전달 시 this

[4, 5, 6].forEach(obj.logValues); 이렇게 사용해야하는데
간혹가다 [4, 5, 6].forEach(obj.logValues(1, 4)); 이렇게 사용하는 경유가 있는데
매개변수까지 넣어줘야 하는 거 아니냐고 하는데,
이렇게 쓰게 되면 매게변수로 쓰는게 아니라 함수의 결과로 넣에 되는 것이다.

함수로 매개변수로 넣는다는건 -> 함수 그 자체로 넣어야 한다는 것

[4, 5, 6].forEach(obj.logValues); 이렇게 썼을 때 원하지
않는 결과가 총 3번 출력되었다.

obj.logValues를 넣었기 때문에 매서드를 넣었다고 생각하지만
이는 매서드의 형태처럼 보이지만 무엇을 넣었냐면

function(v, i) {
        console.log('>>> test start');
        if (this === global) {
            console.log('this가 global입니다. 원하지 않는 결과!');
        } else {
            console.log(this, v, i);
        }
		
        console.log('>>> test end');
	}

결국 나는 위 코드에서 function에서 시작된 이 자체의 함수를
넣어줬을 뿐이다. 이 매서드로서의 호출은
호출만 해줘야지 매개변수로 무언갈 넘기려고 하면 안된다.

이게 왜 콜백함수는 함수인지를 보여주는 것이다
함수 자체로 출력만 필요로 한다.

콜백함수_내부 this에 다른 값 바인딩

closure 방식 (다음주차에 자세한 설명)
: 현재 함수가 끝남음에도 영향력을 끼친다.

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

여기서 어느 부분이 func에 담겨있냐면
function () { console.log(self.name); }; => (팁으로 return 다음걸 보면 됨.)
이 부분이 지금 들어가 있는 것이다.
근데 이 방식의 단점은 this를 사용하지 않는데 있다는 것이다.
depth가 깊기도 하고 번거롭고 귀찮은 작업이다. (위의 방식)

그렇다면 this를 빼버리면 어떨까?

var obj1 = {
	name: 'obj1',
	func: function () {
		console.log(obj1.name);
	},
};

setTimeout(obj1.func, 1000);
첫번 째 보다 간결해보이긴 하지만
this를 사용하지 않으면서 결과만을 위한 코딩이 되었다.
즉 이 코드는 짧아보여도 10점짜리 코드인것이다.


// bind
var obj1 = {
	name: 'obj1',
	func: function () {
		console.log(this.name);
	}
};

// var boundObj1 = obj1.func.bind(obj1);
// setTimeout(boundObj1, 1000);

var obj2 = {name: 'obj2'};
setTimeout(obj1.func.bind(obj2), 1500);

아래 boundObj1 obj1funcbind를 해서 obj1을 묶어주고
obj1이 this로써 묶이고 obj1 객체가 this로 묶이고
변수 obj1의 객체 내부 함수에있는 this는 obj1이랑 묶이는 것이다.

아래의 obj2의 경우 obj1.func.bind까진 맞는데 obj2라는 객체를 bind했다.
obj1가 아닌 obj2가 실행된다. -> 새로운 객체를 this.bind 한 것.

즉 어떤 this든 bind해서 사용할 수 있다는 것을 보여줬다.

0개의 댓글

관련 채용 정보