Using Javascript to link object-oriented programming methods to events and better understand the 'this' keyword

I am currently learning OOP Javascript but struggling with understanding the this keyword and working with events.

My goal is to bind a common event to multiple DOM objects while storing data about these objects in a global container for better performance.

Here is a simplified version of what I am trying to do:

function ClassThatDoesSomething() {
    /* holds node ids for processing in this.init */
    this.nodes = new Array();

    /* stores processed node data for quick access */
    this.nodeData = new Array();

    this.addNodes = function(/* ids */) {
        /* appends node ids to local variable (this.nodeData) */
    }

    function init() {
        /* gathers data from all nodes that were 
           added before and stores it in this.nodeData */

        /* the issue here is that 'this' refers to the window element*/

        addEvent(window,'scroll',this.scroll);
    }

    function scroll() {
        /* perform actions when user scrolls the page */

        /* 'this' also references the window element here */
    }
    addEvent(window,'load',this.init);
}

Later, in the document body, I could simply do this:

var Ctds = new ClassThatDoesSomething();

And then, add DOM elements like this:

Ctds.addNodes(ids);

No additional implementation code would be needed.

QUESTION: How can I access the instance of the JS class in the init and scroll methods instead of the window element.

It doesn't necessarily have to be done through the this keyword, but I haven't been able to find an alternative solution yet.

P.S.

  • addEvent is a basic function for attaching events, ensuring compatibility with IE and Firefox.
  • The code I currently have works fine in a procedural manner, but I am looking to refactor it using OOP principles.
  • As a side note, I've heard conflicting opinions about using getter/setter methods in JavaScript, is it acceptable to use them?

Answer №1

I have observed that the methods init and scroll are not defined as instance methods in this case.

Therefore, you just need to add init to the load event without using this.init:

addEvent(window,'load',init); // "this." is not required

Similarly:

addEvent(window,'scroll',scroll);

If you do decide to make them class methods (e.g. this.scroll and this.init), you can store a reference to this and use it in an anonymous function passed to addEvent:

var self = this;

this.init = function() {
    addEvent(window, 'scroll', function() {
        self.scroll()
    })
};

this.scroll = function() { /* ... */ };

addEvent(window,'load',function() {
    self.init()
});

This concept is known as a closure.

Answer №2

var MyObject = function() {
    this.property = "value";
    var self = this;
    function innerFunction() {
        manipulateProperty(self.property);
    }
}

Answer №3

this remains undefined until the function is executed. When you add an event listener, you are actually passing a function that does not retain its original scope. As a result, when the specified event occurs, the function is executed within the scope of the window object, causing this to refer to window. To ensure the function runs in a specific scope, you can create a new variable, like so:

var that = this;
...
addEvent(window,'scroll', function() {
    that.scroll()
});

Answer №4

Create a new function within the Function prototype that enables the binding of any function to any object:

Function.prototype.bind = function(object) {
   var __method = this;
   return function() {
      return __method.apply(object, arguments);
   };
};

Keep your event handlers organized within the instance:

function ClassThatPerformsAction() {

  this.events = {
    init: ClassThatPerformsAction.init.bind(this),
    scroll: ClassThatPerformsAction.scroll.bind(this),
    etc: ClassThatPerformsAction.etc.bind(this)
  };
  ...
}

Now, when you refer to your events, they will automatically be bound to the class instance. For example:

function init() {
  addEvent(window,'scroll',ClassThatPerformsAction.events.scroll);
}

Answer №5

Closures can be utilized in this scenario:

function ObjectWithFunctionality() {
    var obj=this;
    // ...

    function initialize() {
        addListener(window,'scroll',obj.scroll);
    }
}

Answer №6

Follow these steps:

let CustomClass = function() {
    /* store node ids for processing in this.init */
    this.nodes = [];

    /* store processed node data for quick access */
    this.nodeData = [];
}

CustomClass.prototype.addNodes = function(/* ids */) {
    /* append node ids to local variable (this.nodeData) */
}

CustomClass.prototype.init = function() {
    /* collect data from all nodes that were added before and store it in this.nodeData */

    /* 'this' refers to the window element here */

    addEvent(window, 'scroll', this.scroll);
}

CustomClass.prototype.scroll = function() {
    /* perform actions when user scrolls the page */

    /* 'this' also refers to the window element here */
}

addEvent(window, 'load', this.init);

Answer №7

If you're facing some difficulties, try implementing this solution:

function ClassThatPerformsAction() {
...
    this.This = this;
...
}

Subsequently, within those troublesome functions, utilize 'This'.

Expecting this to be useful for you.

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

Variability in the values returned by the useState hook

Currently, I am working on developing my initial user signup form, and I have encountered a challenge that seems relatively simple to resolve but goes beyond my current expertise. The issue pertains to the helperText for an MUI select component which is no ...

Tips for regularly retrieving information from a psql table

I have a scenario where I am retrieving data from a psql table and converting it into a JSON array to be used for displaying a time series chart using JavaScript. The data that is passed needs to be in the form of an array. Since the data in the table get ...

Verify that the user visits the URL in next.js

I need to ensure that a function only runs the first time a user visits a page, but not on subsequent visits. For example: When a user first opens the HOME page, a specific condition must be met. When they then visit the /about page, the condition for th ...

Get JSON data through AJAX using two different methods

Help needed: JSON request issue with XMLHttpRequest var xhr = new XMLHttpRequest(); function elenco_studenti() { var url = "/controller?action=student_list"; xhr.responseType = 'text'; xhr.open("GET", url, true); xhr.onreadystat ...

Issue with state not being updated upon clicking "Save" button

After setting multiple items in the TransferList component provided by Material-UI, I am encountering an issue when trying to update a state upon clicking "Save". The problem is that the state does not update immediately after clicking "Save"; it requires ...

Using NodeJS and Express: redirection fails to load the specified endpoint

My current project involves a simple e-commerce web application running on localhost built with nodejs and express. Admins are required to register in order to gain access to functionalities such as adding, editing, and removing products from the product l ...

Protractor sendKeys method on Modal dialog is failing due to element visibility issues

I seem to be facing a strange issue with protractor. My challenge lies in testing a form that is situated within a modal. Although I am able to verify that the modal is indeed open, I encounter difficulties when attempting to sendKeys to the input fields. ...

Is the Vue2 Template compiler malfunctioning?

When compiling my code using webpack(^5.51.1) and vue-loader(^17.0.0), I encountered an issue while trying to run an older project. The error message displayed is as follows: [webpack-cli] Failed to load '/var/www/webpack.config.js' config [webpa ...

How to prevent selecting future dates in Material UI date picker

Is there a way to prevent selecting future dates in the material UI datepicker? I noticed that it doesn't seem to have any prop options like disableFuture or past. For those interested, here's the link to the github repository sandboxlink ...

Have the quotes within my markup been replaced with HTML entities?

Currently, I am working on a content page that uses a master page which includes a text box and a button. My goal is to have the button execute some JavaScript code before performing any other actions. At the moment, I am in the testing phase of this JavaS ...

using javascript to get array element when hovering

I am currently exploring ways to retrieve and display the value of a div tag created with a 2D array using JavaScript. I have considered using onclick or onmouseover, but so far, neither approach has worked as expected. I am looking for a solution that avo ...

Error: Attempted to access undefined property 'renderMenu' in a promise without handling it

I am looking to generate a dynamic menu based on the JSON data provided below: [ { "teamId": "10000", "teamName": "Laughing Heroes", "superTeamId": "", "createTime": "2017-06-25T06:07:45.000Z", "createUserId": null }, { "team ...

Do you notice a discrepancy in the number returned by Javascript's Date.getUTCDate() when the time component is set to

Consider the following code snippet: const d = new Date('2010-10-20'); console.log(d.getUTCDate()); If you run this, the console will output 20. However, if you modify the code like so: const d = new Date('2010-10-20'); d.setHours(0, ...

Having issues with a basic javascript bookmarklet that isn't functioning properly due to a clientside validation script error. Any suggestions on how

Seeking assistance, as I am facing a challenge with transferring a large amount of data from a spreadsheet into a web form located at . Manually inputting this data is time-consuming, so I explored different options and concluded that a javascript bookmark ...

Customizing blockquote styling in QuillJS with a unique class

Currently, I am exploring a method to include a custom class when the user selects the blockquote toolbar button. When the blockquote is clicked, it generates the following element: <blockquote class="ql-align-justify">this is my quoted tex ...

What are different ways to modify a bytearray within a file using angular js, whether it is an .xlsx or other

I received a bytearray response from my API that was converted from a .xlsx file. I now need to open or download this bytearray in the browser after converting it back to its original file extension. Can anyone provide guidance on how to achieve this? I ...

The API call for /api/users/create was resolved without a response, which could potentially lead to requests getting stuck. This issue was detected in

I've developed an API endpoint to manage user account creation within my Next.js application, utilizing knex.js for handling queries. Despite this, I keep encountering the following error: API resolved without sending a response for /api/users/create ...

Troubleshooting: Issue with onclick event in vue.js/bootstrap - encountering error message "Variable updateDocument not found"

As a newcomer to frontend development, I have a basic understanding of HTML5, CSS, and Javascript. Recently, I started working on a vue.js project where I integrated bootstrap and axios. Everything seemed to be working fine until I encountered an issue whe ...

Executing an external function on an element as soon as it is created in AngularJS: tips and tricks

I am looking to implement a function from an external library that will be executed on each item as it is created in AngularJS. How can I achieve this? Here is the code snippet of my application. var app = angular.module('app', []); app.contr ...

Does the resolve function within a Promise executor support async operations?

I'm trying to wrap my head around the following code: function myPromiseFunc() { return new Promise((resolve) => { resolve(Promise.resolve(123)); }); } We all know that the Promise.resolve method immediately resolves a Promise with a plain ...