다른 코드의 인자로 넘겨주는 함수.
콜백함수를 넘겨받은 코드는 적절한 시점에 실행.
콜백(callback)의 뜻은 '되돌아 호출해달라'는 뜻.
var callback = function(){
console.log('이건 setInterval이 1초마다 호출하는 함수입니다.');
}
setInterval(callback,1000);
setInterval
함수는 인자로 받은 시간마다 callback함수를 호출하는데, 여기서 callback함수를 1000ms(1초) 사용자가 직접 실행하지않고, setInterval
이 1초마다 알아서 실행을 시켜줌. 즉, callback
함수 실행에 대한 권한을 setInterval
함수가 위임받아서 알아서 실행 시킨다고 보면 됨.
const newArr = [];
[10,20,30].forEach(function(value,index,arr){
newArr.push([ value, index, this[index],arr ]);
},[100,200,300]);
console.log(newArr); //[[10,0,100,[10,20,30]],[20,1,200,[10,20,30]],[30,2,300,[10,20,30]]]
[10,20,30]
배열에 forEach
메서드를 실행. 첫 번째는 forEach
메서드가 호출 할 callback함수, 두번째는 forEach
메서드안에서 this로 인식할 대상인 thisArg
가 들어감(생략가능).
arr.map(callback(currentValue[, index[, array]])[, thisArg])
forEach
메서드는 요소를 하나하나씩 꺼내어 콜백함수를 실행. 콜백함수의 내용은 newArr
배열에 배열의 요소,배열의 위치값, 그리고 this로 인식한 대상 배열의 위치 값을 담은 배열을 newArr
에 넣는 일을 수행.const newArr = [];
[10,20,30].forEach(function(index,value){
newArr.push([ value, index, this[index] ]);
},[100,200,300]);
console.log(newArr); //[[0,10,undefined,[10,20,30]],[1,20,undefined,[10,20,30]],[2,30,undefined,[10,20,30]]]
forEach
메서드를 jQuery
의 each
메서드처럼 썻다고 가정하에 작성.( each
메서드의 콜백함수에는 첫 번째는 index
와 두 번째는 value
가 옴)newArr
배열의 값을 콘솔로 출력하면, value
는 값의 위치, index
는 값 ,3번째는 thisArg
배열의 index
위치의 값인 undefined
가 들어가 있음. 사용자는 jQuery
의 each
처럼 분명 순서를 바꿔서 사용하겠다고 작성했지만, 이름은 사용자가 명명할것일뿐, 해당 값은 사용자가 매개변수 명을 다르게 변경을 해도 성격은 똑같음. 즉, forEach
메서드에서 인자로 받는 콜백함수는 forEach
함수가 제어권을 가지고있어서, 원하는 대로 배열이 돌아가기위해서는 메서드의 규칙을 따라야 함.this
에서 작성했듯 콜백함수에서의 this
는 기본적으로 전역 객체를 참조하지만, 제어권을 넘겨받은 코드에 별도로 지정된 경우에는 전역 객체가 아닐수가 있음.Array.prototype.forEach = function(callback,thisArg){
for(var i=0;i<this.length;i++){
callback.call(thisArg || window, this[i],i,this);
}
}
위에 소스를 보면 콜백함수를 호출 할 때 call
을 붙여서 호출하는데 콜백함수 내부에서 this
는 thisArg
에 값이 있으면 thisArg
이고 없으면 전역 객체를 가리킴. 그래서 콜백함수의 this
도 제어권을 넘겨받은 코드에서 call
과 apply
메서드를 통해서 this
의 값도 명시적으로 바인딩 됨.
setTimeout(function(){console.log(this);},1000); // window
document.body.innerHTML='<button id="a">클릭</button>';
document.querySelector('#a').addEventListener('click',function(e){
console.log(this,e); // <button id="a">클릭</button>, MouseEvent{...}
});
setTimeout
에서 인자로 받은 콜백함수안의 this
는 값을 바인딩하지않고 그대로 호출했기때문에 전역객체를 가리킴.addEventListener
에서 인자로 받은 콜백함수안의 this
는 내부에서 콜백함수를 호출할때 this
값을HTML요소
값을 바인딩하여 호출했기때문에 로그에는 button
요소를 가리킴.array function
문법을 이용했다면, this
값을 바인딩하는 과정이 제외 되기 때문에 스코프 체인상 가까운 전역 객체를 가리킴. var obj = {
array:[1,2,3],
logValues:function(v,i){
console.log(v,i,this);
}
}
obj.logValues(1,2);//1,2,{array:[1,2,3],logValues:f}
[4,5,6].forEach(obj.logValues);//[4,0,Window][5,1,Window],[6,2,Window]
obj
객체안의 logValues
를 호출시 this
는 obj
객체를 가리키는것은 당연.forEach
의 콜백함수를 obj.logValues
를 전달하는 순간 obj
객체와는 연간성이 사라져, 배열을 반복할때마다, this
의 값은 전역 객체를 가리키게 됨.this
객체를 다른 변수에 담아서 콜백함수에서 호출시 다른 변수 값으로 사용bind
를 이용한 this
객체에 다른값 바인딩.var obj1 = {
name:'obj1',
func:function(){
console.log(this.name);
}
}
setTimeout(obj1.func.bind(obj1),1000); //obj1
var obj2 = {name:'obj2'};
setTimeout(obj1.func.bind(obj2),1000); //obj2
콜백 지옥이란?
콜백 함수를 익명함수로 전달되는 과정이 계속 반복되어 들여쓰는 코드의 수준이 감당이 힘들정도로 깊어지는 현상.
var name = '';
var callback=function(param){
name = param;
console.log(name);
setTimeout(callback2,1000,'obj2');
}
var callback2=function(param){
name = param;
console.log(name);
setTimeout(callback3,1000,'obj3');
}
var callback3=function(param){
name = param;
console.log(name);
setTimeout(callback4,1000,'obj4');
}
var callback4=function(param){
name = param;
console.log(name);
}
setTimeout(callback,1000,'obj1');
new Promise(function(resolve,reject){
setTimeout(function(){
var name = 'obj1';
console.log(name);
resolve(name);
},1000);
}).then(function(prevName){
return new Promise(function(resolve,reject){
setTimeout(function(){
var name = `${prevName} obj2`;
console.log(name);
resolve(name);
},1000);
})
}).then(function(prevName){
return new Promise(function(resolve,reject){
setTimeout(function(){
var name = `${prevName} obj3`;
console.log(name);
resolve(name);
},1000);
})
})
Promise
인스턴스에서 인자로 넘겨주는 콜백함수안의 비동기 처리 후 resolve
를 호출하면 then
(다음) 메소드를 호출하면, 프로미스 객체를 반환하기 때문에, 이어서 비동기 방식을 호출 할 수 있어 들여쓰는 코드를 줄일 수 있음.(메소드 체이닝 기법)
var func = function(name){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve(name)
},1000)
});
};
var callFunc = async function(){
var names = '';
var call1 = async function(name){
names = `${names} ${await func(name)}`;
}
await call1('obj1');
console.log(names);
await call1('obj2');
console.log(names);
await call1('obj3');
console.log(names);
await call1('obj4');
console.log(names);
}
callFunc();
async/await
는 비동기를 마치 동기방식처럼 사용할수있는 방식이며, await
안에 비동기처리가 끝날때까지 아래에 소스는 작동하지 않음. 비동기 방식을 수행하고자 하는 함수 앞에 async
를 넣고, 함수 내에서 비동기를 작업하는 위치에 await
를 넣으면 됨.(단, await
가 들어가는 함수는 Promise
객체를 리턴해야함)
this
(기본적으로 전역객체를 바라보지만, 임의로 바꾸고 싶은 경우는 bind
메서드를 통해 임의로 할당.Promise
, async/await
등 여러가지 방법들이 나오고 있음.