function debounce(fn, delay) {
var timer
return function () {
var context = this
var args = arguments
clearTimeout(timer)
timer = setTimeout(function () {
fn.apply(context, args)
}, delay)
}
}
I'm curious about the purpose of context = this in this code. I don't understand the code very well.
Secondly, fn.apply (context, args) This part is also not well understood. Is there a special reason to bind this? You want to use the debounce function as an util function throughout the project.
export function debounce(fn, delay) {
var timer;
return function () {
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(this, args);
}, delay);
};
}
- I want to know the difference between the last chord and the first chord
CodePudding user response:
var context = this
The reason why you would put this
into a different variable in this code is simply that
function(){}
has a different this
value based on where it gets called. In this case it's called from setTimeout
as a callback, which means that this
would be whatever it is inside of setTimeout
instead of what it was when the debounce inner function was called
You could get around this pretty easily in modern JavaScript using arrow functions, which have a lexical this
- this
is based on where the function was created instead of where it is called.
This would be the equivalent code to the initial version with the correct this
binding.
function debounce(fn, delay) {
var timer
return function () {
var args = arguments
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
fn.apply(context, args)
function#apply
allows you to run a function with both a specific this
value applied to it as well as passing in multiple arguments in an ergonomic way. Before we had rest syntax, function#apply
was the only approach to this, now you can actually just use fn(...args)
in modern javascript (assuming you don't have to explicitly bind the this
value of the function). Just keep in mind that this
is an incredibly confusing concept for nearly everyone.
The reason why you would bind context
in general in the function as defined, is just so that debounce
is more generic and more capable of being called in different circumstances. For example, in this case, we can use this
to increment a counter based on the element that the function was called on.
In practice, you wouldn't want the same debounced function put on both, you'd want to have one function and then debounce it twice, otherwise you could end up "canceling" a click on one by clicking on the other, but it's a good example of how this
can make it more functional.
function debounce(fn, delay) {
var timer
return function() {
var args = arguments
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
const debounced = debounce(function() {
this.dataset.numClicks = (Number.parseInt(this.dataset.numClicks || 0)) 1;
this.innerText = `Clicked ${this.dataset.numClicks} Times!`
console.log(this.innerText)
}, 500);
document.querySelectorAll('button').forEach(el => el.addEventListener('click', debounced));
div {
height: 100%;
width: 100%;
color: black;
background: pink;
}
<button>Click me!</button>
<button>Click me!</button>
CodePudding user response:
Pretty easy to see what the difference is when you test it out.
function debounce1(fn, delay) {
var timer
return function() {
var context = this
var args = arguments
clearTimeout(timer)
timer = setTimeout(function() {
fn.apply(context, args)
}, delay)
}
}
function debounce2(fn, delay) {
var timer;
return function() {
var args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(this, args);
}, delay);
};
}
var button = document.querySelector('button');
button.addEventListener('click', debounce1(function(){console.log("1", this);}, 500));
button.addEventListener('click', debounce2(function(){console.log("2", this);}, 500));
<button>Click</button>
You maintain the context of what triggered the function vs using the window object in the timeout.