2
    Function.prototype.defer = function(ms) {
    let f = this
    return function(...args) {
        setTimeout(()=>this.apply(this, args), ms); //**
    }
};


function f(a, b) {
  alert( a + b );
}

f.defer(1000)(1, 2); // shows 3 after 1 second

So the above code gives an error saying "this.apply is not a function". However, if I change the line with (**) to

setTimeout(()=>f.apply(this, args), ms);

the code runs fine, even though f still references "this". What gives?

3
  • 1
    But it's not the same "this". Just check its content. Commented Mar 16, 2019 at 9:48
  • 2
    the this you are referencing gives reference to global object this inside setTimeout function, but when you are storing this in local variable f that f is pointing to the this of the function and not the global object this Commented Mar 16, 2019 at 9:53
  • 1
    The ‘this’ keyword in JS can be a little tricky at times. Read more here Commented Mar 16, 2019 at 9:59

4 Answers 4

1

Let's have a look at the code provided in the question to see why one works and the other doesn't.

Let's first take a look at the functioning example:

Function.prototype.defer = function (ms) {
  let f = this;
  return function(...args) {
    setTimeout(() => f.apply(this, args), ms);
  };
};

function f(a, b) {
  alert(a + b);
}

f.defer(1000)(1, 2); // shows 3 after 1 second
// translates to
setTimeout(() => f.appy(this, [1, 2]), 1000);
//                       ^
// here `this` refers to the global object (window)

Let's have a look at the non-working example:

Function.prototype.defer = function (ms) {
  return function(...args) {
    setTimeout(() => this.apply(this, args), ms);
  };
};

function f(a, b) {
  alert(a + b);
}

f.defer(1000)(1, 2); // shows 3 after 1 second
// translates to
setTimeout(() => this.appy(this, [1, 2]), 1000);
//                ^         ^
// here `this` refers to the global object (window)

Since this in the above context points to the global object (window) you could also write this as:

setTimeout(() => window.appy(window, [1, 2]), 1000);

Since window is an object and not a function this explains the error you're getting.

Sign up to request clarification or add additional context in comments.

1 Comment

Like others already pointed out every function () { ... } body introduces a new this binding. this in defer points the receiver (f in f.defer(1000)). The anonymous function returned by defer is called without receiver thus this will point to the global object.
1

Every function has it's own this, which is not necessary identical with the outer this.

You could bind this to the returned function for the parameters.

Inside of this function this stays, because you take an arrow function, where the outer this is taken.

Function.prototype.defer = function(ms) {
    return function(...args) {
        setTimeout(() => this.apply(this, args), ms); //**
    }.bind(this);
};

function f(a, b) {
    console.log(a + b);
}

f.defer(1000)(1, 2); // shows 3 after 1 second

1 Comment

How about adding an explanation on the actual problem so TO understands why it's not working?
0

the function's this would change, just like when you have the same parameter name (ms in the following example) as outer scope.

Function.prototype.defer = function(ms) {
    let f = this
    return function(ms,...args) {
        setTimeout(() => f.apply(this, args), ms); //**
    }
};

function f(a, b) {
    console.log(a + b);
}

f.defer(100000)(1000, 1, 2); // shows 3 after 1 second (not 100 second)

Comments

0

The use of this is different between arrow functions and regular functions. For arrow functions they each have their own this.

But when this is used in other functions there is a more complex set of rules, and often it depends on where the function is called from. Here's a list of those rules, if you're interested: https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch2.md#review-tldr

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.