일정 시간이 지난 후 지정한 함수를 호출할 수 있도록 하는 걸 호출 스케줄링이라고 합니다.
호출 스케줄링은 다음과 같은 방법으로 구현합니다.
setTimeout : 일정 시간이 지난 후 함수 실행setInterval : 일정 시간 간격마다 함수 실행지정한 시간이 지나면 넘겨준 함수를 실행합니다.
let timerId = setTimeout(func|code, [delay], [arg1], [arg2], ...)
타이머 식별자 (ID) 를 반환, 스케줄링을 가리킴func|code : 실행하려는 함수 (스케줄링할 대상!)delay : 밀리초 단위, 실행 전 대기하는 시간arg : 함수에 넘겨줄 인수function sayHi(who, phrase) {
alert( who + ' 님, ' + phrase );
}
setTimeout(sayHi, 1000, "홍길동", "안녕하세요."); // 홍길동 님, 안녕하세요.
1초 후에 sayHi 함수를 실행합니다.
setTimeout 으로 한 스케줄링은 clearTimeout 으로 취소 가능합니다.
setTimeout 의 결과로 반환된 타이머 식별자를 clearTimeout 에 인수로 넘겨주면 됩니다.
let timerId = setTimeout(...);
clearTimeout(timerId);
스케줄링을 취소하면 setTimeout 에서 넘겨준 함수가 시간이 지나도 실행되지 않습니다.
setInterval 은 setTimeout 과 동일한 문법에 동일한 인수를 받습니다.
그러나 setTimeout 은 한 번만, setInterval 은 주기적으로 함수를 실행합니다.
let timerId = setInterval(func|code, [delay], [arg1], [arg2], ...)
타이머 식별자 (ID) 를 반환, 스케줄링을 가리킴func|code : 실행하려는 함수 (스케줄링할 대상!)delay : 밀리초 단위, 실행 전 대기하는 시간arg : 함수에 넘겨줄 인수setInterval 또한 clearInterval 로 스케줄링을 취소할 수 있습니다.
방식은 clearTimeout 처럼, 타이머 식별자를 clearInterval 에 인수로 넘겨줍니다.
중첩 setTimeout 으로 setInterval 함수의 동작을 구현할 수 있습니다.
let timerId = setTimeout(function tick() {
alert('째깍');
timerId = setTimeout(tick, 2000); // (*)
}, 2000);
중첩 setTimeout 은 다음 번 호출을 원하는 방식으로 조정할 수 있기 때문에
setInterval 보다 더 유연합니다.
또한, setInterval 은 지연 간격을 보장하지 않지만 중첩 setTimeout 은 보장합니다.
delay 에 1000 을 지정했을 때, setInterval 은 각 함수의 호출이
정확히 1000ms 간격으로 이뤄지지 않습니다.
이는 setInterval 이 함수의 실행 시간도 delay 에 포함하기 때문입니다.
따라서, 함수 실행에 300ms 가 걸린다고 하면 다음 함수 호출까지 걸리는 시간은 700ms 가 됩니다.
반면, setTimeout 은 이전 함수의 실행 종료 이후 다음 함수 호출에 대한 계획을 세웁니다.
따라서 이전 함수가 끝나는 시점과 다음 함수가 시작하는 시점 사이의 지연 간격이 지정한 1000ms 로 일정합니다.
객체 메서드를 콜백으로 전달할 때 this 정보가 사라집니다.
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
setTimeout(user.sayHi, 1000); // Hello, undefined!
객체 메서드를 넘겨주는 것은 다음과 같은 동작이라고 볼 수 있습니다.
let f = user.sayHi;
setTimeout(f, 1000); // user 컨텍스트를 잃어버림
앞에 호출하는 객체가 없는 f 는 this 가 user 가 아닙니다.
이럴 때 함수에 this 를 고정한 후 넘겨줘야 합니다.
모든 함수는 내장 메서드 bind 를 제공합니다.
func.bind(context) 는 함수처럼 호출 가능한 특수 객체를 반환하고,
이 객체를 호출하면 this 가 context 로 고정된 함수 func 를 반환합니다.
let bound = func.bind(context, [arg1], [arg2], ...);
this 뿐만 아니라 인수도 고정할 수 있습니다.
자바스크립트에서 this 는 함수 호출 방식에 따라 다르게 정해집니다.
함수를 호출하는 방식은 다음과 같습니다.
각 방식에 따라 다르고, 다른 함수에 내부에 있는지 아닌지도 영향을 미칩니다.
function hello(){
console.log(this);
}
hello(); // window
this === window
전역 공간에 작성된 함수를 호출하면 전역 객체 window (브라우저 환경의 경우) 를
this 에 바인딩 합니다.
또한 다른 함수의 내부에 위치한 함수는 선언 위치에 관계 없이 this 는 전역 객체에 바인딩됩니다.
이는 메소드의 경우도 마찬가지 인데요, 메소드 내부의 함수가 외부의 맥락을 이어받지 못하게 됨을 의미합니다. 설계 단계의 결함이라고 하네요.
객체의 프로퍼티인 함수의 경우, 해당 메서드를 호출한 객체에 this 를 바인딩합니다.
즉, 메서드의 this 는 자신을 호출한 객체입니다.
const student = {
greet: function () {console.log(this);}
}
student.greet(); // student
화살표 함수는 자체 this 바인딩이 없어 선언된 환경의 this 를 이어받습니다.
const student = {
study: () => {console.log(this);},
greet: function () {console.log(this);},
hello: function () {
const hi = () => console.log(this);
hi();
}
}
student.study(); // window
student.greet(); // student
student.hello(); // student
const teacher = student.hello;
teacher(); // window
const foo = {
bar: function(){
const test = () => { console.log(this); };
test();
return test;
}
};
const how = foo.bar();
how(); // {bar: f}
// 클로저
// foo 의 메서드로 실행한 bar 함수에서 test 가 선언되므로 this 는 이떄의 foo 객체
const who = foo.bar;
who(); // window
// foo 객체에서 bar 메서드만 빼서 who 에 옮긴 후 who 를 실행할 때 test 가 선언되므로 this 는 window
그래서 화살표 함수의 경우 호출 시점이 아니라 선언 시점의 환경에 따라 this 가 정해집니다.
콜백 함수로 호출했을 경우는 실행 컨텍스트가 활성화될 때 this 가 바인딩된다는 것을 기억하면 됩니다.
즉, 아무리 넘겨줄 때 obj.func 이렇게 넘겨줘도 실행 컨텍스트는 콜백을 받은 주체 안에서 생성된다는거죠.
const obj = {
bar: function(){
console.log(this);
}
};
function call(cb){
cb(); // 일반 내부 함수로 실행
};
call(obj.bar);
위처럼... 내부 동작을 생각하면 그냥 일반적인 내부 함수 호출과 다를 바 없습니다.
이러니까 명시적 바인딩을 안 해주면 this 가 그냥 전역 객체가 되죠.
물론 call 함수 내에서 cb 의 this 를 따로 지정해주면 동작이 바뀝니다.
new 연산자를 사용하여 호출하는 경우, this 는 생성자 함수에 의해 만들어지는 인스턴스 객체를 가리킵니다.
화살표 함수는 다음과 같은 특징을 갖습니다.
this 바인딩이 없음arguments 바인딩이 없음보통 함수는 매개변수 이외에도 this 와 arguments 가 전달됩니다.
그러나 화살표 함수에는 이러한 암묵적 전달이 일어나지 않습니다.
따라서, 화살표 함수에 없는 this 나 arguments 를 참조하려고 하면
렉시컬 스코프에 따라 기억한 상위 스코프... 외부의 컨텍스트를 참조합니다.
이에 따라 내부함수로 사용된 화살표 함수는 외부 함수의 this 와 arguments 를 동일하게 이어받습니다.
그래서 화살표 함수는 객체의 메서드로 쓰지 않습니다.
메서드로서 호출해도 자체 this 바인딩이 없어서 외부의 this 인 전역 객체를 받아오기 때문입니다.