What causes the difference in behavior between using setInterval() with a named function as an argument versus using an anonymous function?

I can't seem to figure out why using the function name in setInterval is causing issues, while passing an anonymous function works perfectly fine.

In the example that's not working (it's logging NaN to the console and before the first call, this.counter++ returns undefined as it couldn't find the variable?)

export class MyClassName {
 counter = 0;

 startInterval(){
   setInterval(this.myFunc , 1000)
 }

 myFunc(){
   this.counter++;
   console.log(this.counter)
 }
}

However, when changing startInterval like below, it works correctly

startInterval(){
  setInterval(() => this.myFunc() , 1000)
}

And in the HTML we have:

<button (click)="startInterval()">Start</button>

Answer №1

When passing in a function reference without executing it, as shown in the first example, the function runs in the global context where `this` is either undefined or refers to the `Window` object. This can be confirmed by logging the value of `this.constructor.name`:

class MyClassName {
 counter = 0;

 // A function name is passed in but not executed yet.
 // It will be run globally by setInterval.
 startInterval(){
   setInterval(this.myFunc, 1000)
 }

 myFunc(){
   // When running in a global context, `this` no longer points to our instance.
   console.log(this.constructor.name);
   this.counter++;
   console.log(this.counter)
 }
}

const mc = new MyClassName();

mc.startInterval();

The second example demonstrates that arrow functions capture the `this` from where they are declared, not where they are executed. Therefore, even though the arrow function will run in the global context, the `this` of the class is retained below:

class MyClassName {
 counter = 0;

 // Arrow functions take the `this` from where they are declared.
 // Thus, the `this` of the class is preserved here, despite the arrow function
 // running in the global context.
 startInterval(){
   setInterval(() => this.myFunc(), 1000);
 }

 myFunc(){
   console.log(this.constructor.name);
   this.counter++;
   console.log(this.counter)
 }
}

const mc = new MyClassName();

mc.startInterval();

A detailed explanation of how `this` behaves with `setInterval` and arrow functions can be found in the MDN documentation on arrow functions.

Answer №2

The issue lies in the usage of the this keyword. When it comes to JavaScript, anonymous or arrow functions do not establish a reference for this to point back to the function caller. On the other hand, a traditional function created with the function keyword will keep track of the caller within this.

As a result, in the first scenario, startInterval() is triggered by the button element, which does not possess a counter variable. Meanwhile, in the second scenario, the this keyword points to the external scope's this, specifically the window object. It can be assumed that MyClassName is generated under the window object, hence the presence of the counter.

If you'd like to delve deeper into this topic, check out:

Answer №3

The reason for the error is that your use of this is causing the function to be called, resulting in myFunc being undefined. To understand more about the context of this, you can refer to resources like this article and this one.


You can confirm this issue by logging this.myFunc. A similar problem may occur with this.counter if it is accessed.

let counter = 0;

const startInterval = () => {
  // Results in undefined as it does not exist.
  console.log(this.myFunc);
  setInterval(this.myFunc, 1000);
};

startInterval();

const myFunc = () => {
  this.counter++;
  console.log(this.counter);
};

To resolve this issue, rearrange the functions and eliminate references to this in your code.

let counter = 0;

const myFunc = () => {
  counter++;  // Also remove 'this' from here.
  console.log(counter);
};

const startInterval = () => {
  // Now defined, so it will work correctly.
  setInterval(myFunc, 1000);
};

startInterval();

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Seeking clarification on submitting forms using JQuery - a straightforward query

My goal is to trigger a form submission when the page reloads. Here's what I have so far: $('form').submit(function() { $(window).unbind("beforeunload"); }); $(window).bind("beforeunload", function() { $('#disconnectform&apo ...

Disabling the default validation message in HTML form inputs

Is there a way to change the default message that appears when submitting an empty HTML text input? I would like the box border to turn red instead. Can anyone help me achieve this? Below is the code for the text input box: <div class="input-group ...

Are there alternative methods for handling routes in React, other than using the react-router-dom@latest library?

Currently, I am focused on a frontend project. One of the tasks at hand is to configure the network of routes. During my research, I came across react-router-dom@latest as a potential solution. However, I am curious to explore alternative options availa ...

The Ghostly Glare of Doom: Ionic 2 Strikes on Android

While my application runs smoothly in the browser, I encounter an error when trying to run it on my device. The issue is as follows: 0 758771 log deviceready has not fired after 5 seconds. 1 758797 log Channel not fired: onDOMConte ...

Changing a DOM structure into pure HTML using JavaScript

Looking to convert some HTML into a PDF file using a service that requires form-data as the payload. Is there a way to extract HTML from the DOM and save it as a file for use in the payload? <p>some other HTML</p> <div id="content"> ...

Stopping a build programmatically in Next.js involves implementing specific steps that aim to halt

Is there a method to programmatically halt the execution of npm run build in Next.js when a specific Error occurs within the getStaticProps function? Simply throwing an Error does not seem to stop the build process. ...

mysterious supplier factoryprovider <- factory <- angular js controller

I'm encountering an issue with injecting dependencies from a service to a controller. Despite adding it, I keep receiving the following error: Unknown provider: websiteFactoryProvider <- websiteFactory <- listCtrl My main goal is to display ...

express has a req.body that is devoid of any content

When making a request to my local server in my React app, the code looks like this: fetch("http://localhost:4000/signup", { method: "POST", mode: "no-cors", body: JSON.stringify({ name: "Joe", lname: "Doe& ...

Check for length validation including spaces in JavaScript

My code includes a functionality that calculates the length of characters in a text area using both JSP and JavaScript: <textarea class="textAreaLarge" id="citation" rows="20" cols="180" name="citation" ...

Generating instances of classes using variables in Typescript

Are there methods to modify the below piece of code in order for it to be compatible with Typescript? public shops: string[] = [ "AShop", "BShop", "CShop", ]; this.shops.forEach((shop, index) => { let instance = new window[shop](index ...

Angular-ui-bootstrap modal failing to display provided data

I have been working on implementing model data into a modal window that opens. The data is passed through a $http.post success and also in failure then() with different titles and button texts. Several data points are being passed to the modal: //.then(){ ...

What is the best way to wrap a call to XMLHttp Request within a $q promise?

I am trying to figure out how to wrap the following code in an AngularJS ui-router resolve section with a $q promise. The goal is to return success or fail based on whether the http request works. Should I encapsulate all of this inside a promise or just ...

Alignment issue with ThreeJS Collada file

I'm currently diving into the world of ThreeJS and I am experimenting with loading collada files into a viewer. My journey began by replicating the code from the Elf colladaLoader demo. I successfully managed to display the model inside an 800px squa ...

What is the best way to refresh a single component in my application without causing the other components to reload?

I've been working on a review application with Vue.js that fetches random facts from an API (https://uselessfacts.jsph.pl/random.json?language=en) and allows users to provide feedback through radio buttons and text inputs. Once submitted, the feedback ...

The synergy of Redux with scheduled tasks

In order to demonstrate the scenario, I have implemented a use-case using a </video> tag that triggers an action every ~250ms as the playhead moves. Despite not being well-versed in Flux/Redux, I am encountering some challenges: Is this method cons ...

I'm having some trouble with my jQuery.get() function in the javascript Saturday(), can anyone help me figure out what I'm doing wrong?

Can anyone help me troubleshoot my jQuery.get() method in the saturday() JavaScript function? Here is the code snippet I have been working on. This is what I have in my index.html file: <html> <head> <title>jVectorMap demo</title> ...

Typescript encounters a failure in typing when an object is destructured

There is a function that returns an object with two properties (res, mes) where one of them could be null: const fetchJSON = <Res, Body>(link: string, body: Body): Promise<{ res: Res; mes: null } | { res: null; mes: Popup }> => { return n ...

encountering difficulties calling setAttribute within a function

I am encountering an issue while attempting to use setAttribute() within toggleDiv(). My IDE does not seem to recognize the function and is throwing an error. How can I resolve this problem so that the function is recognized? This specific case relates t ...

What is the best way to choose the current Div's ID, as well as its Width and Height properties?

Within this section, there are four div elements with varying widths, heights, and colors that appear and disappear when their respective buttons are clicked. I am adding an "activeDiv" class to the visible div in order to easily select it using that class ...

Determining If a setInterval Function is the Sole Factor Preventing an App from Exiting

Is there a method to determine the number of tasks remaining for Node before it automatically exits because all tasks are completed? I am interested in utilizing setInterval but only while the application is still running other processes. I do not want t ...