The execution of a nested object's function that calls a JavaScript function encounters an error

Below is a simple example demonstrating the issue I am facing, which you can also view on JSFiddle here.

While I understand why the issue is happening, I'm unsure of how to resolve it without altering the existing JS structure.

The problem arises when defining prototype functions for JavaScript objects, particularly when there is a nested object at the 2nd level that contains a function calling another function on the parent/root level. This leads to a failure in execution.

In the code snippet provided, the line

this.nestedObject.nested_object_function()
is attempting to invoke the function this.normal_function(), resulting in the error:

Uncaught TypeError: this.normal_function is not a function
    at Object.nested_object_function (VM2493:79)

It seems that the issue stems from this referencing this.nestedObject instead of the parent object.

If this assumption is correct, how can I successfully call the desired function from within the nested object function and access a function from the parent object?

I have also experimented with calling JsLibTest.normal_function() as a test within the

this.nestedObject.nested_object_function()
function, but encountered the same error.


    var JsLibTest = (function (document) {
        "use strict";
    
        var JsLibTest = function (){
          this.init();
        };
    
        JsLibTest.prototype = {
    
          init: function() {
    
            this.normal_function();
    
            this.nestedObject.nested_object_function();
    
          },
    
          normal_function: function() {
              console.log('this.normal_function() ran');
          },
    
          nestedObject: {
          
              nested_object_function: function() {
              this.normal_function();
                console.log('this.nestedObject.nested_object_function() ran');
              },
          }
    
        };
    
        return JsLibTest;
    })(document);
    
    $(document).ready(function(){
      var Sidebar2 = new JsLibTest();
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Answer №1

Your understanding is accurate. When referencing this in a nested object, it will point to the nested object itself rather than the parent object, resulting in the function being deemed undefined.

To solve this issue, you need a method to access the parent object. Typically, objects do not inherently contain information to reference objects that reference them. This is logical considering multiple objects may internally reference the same object.

One approach is to store a reference to the parent object and utilize it in the nested function:

var nested = {
  g() {
    this.parent.f();
  }
};
var parent = {
  f() {
    console.log('called');
  }
};
nested.parent = parent;

nested.g();

Alternatively, you can employ Function.prototype.call (or a similar method) to establish the correct context.

var obj = {
  f() {
    console.log('called');
  },
  g() {
    this.nested.nested_f.call(this);
  },
  nested: {
    nested_f() {
      this.f();
    }
  }
};

obj.g();

Applying the latter solution within the context of your scenario:

var JsLibTest = (function(document) {
  "use strict";

  var JsLibTest = function() {
    this.init();
  };

  JsLibTest.prototype = {

    init: function() {
      this.normal_function();

      // Utilizing .call here to specify the context
      this.nestedObject.nested_object_function.call(this);
    },


    normal_function: function() {
      console.log('this.normal_function() executed');
    },

    nestedObject: {
      nested_object_function: function() {
        this.normal_function();
        console.log('this.nestedObject.nested_object_function() executed');
      }
    }
  };

  return JsLibTest;
})(document);

// invoke it
$(document).ready(function() {
  var Sidebar2 = new JsLibTest();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Answer №2

It is important to note that the scope does not have direct access to the parent. One way to solve this issue is by passing the parent to the nested object. Here's how you can do it:

this.nestedObject.nested_function(this);

Then, in your nested function, you can refer to the parent like this:

nested_function: function(self) {
    self.some_function();
    alert('this.nestedObject.nested_function() was executed');
}

By passing 'this' (parent) as 'self', you can effectively call it from the nested function.

Answer №3

To start, it is important that each Object is distinct and has its own prototype:

this.childObject = Object.create(this.childObject);

var CustomLibraryTest = function() {
      // execute init() function when a new CustomLibraryTest object is created
      this.init();
      // establish parent-child relationship:
      this.childObject.parent = this;
    };

Now, you can reference this.parent within your inner function...

this.parent.custom_function();

If you wish for this to serve as the parent, utilize binding:

var CustomLibraryTest = function() {
      // execute init() function when a new CustomLibraryTest object is created
      this.init();
      // establish parent-child relationship:
      for(i in this.childObject) {
         var element = this.childObject[i];
         if(typeof element === "function") {
             this.childObject[i] = element.bind(this);
         }
       }
    };

For convenience, you can utilize a helper function like this:

getFunction: function(...args) {
  args.reduce((object, key) => object[key], this).bind(this);
}

Usage example:

CustomLibraryTestInstance("childObject", "childobject_function")();

Answer №4

Ah yes, it is indeed correct that the this value within the JSLibTest.prototype.nestedObject function is referencing the nestedObject itself and not the JSLibTest object.

If you wish to keep the same call signature, you can define nestedObject as an immediately invoked function expression (IIFE):

nestedObject: (function() {
  var that = this;

  return {
    nested_object_function: function() {
      console.log(that);
      // this.normal_function();
      alert('this.nestedObject.nested_object_function() was executed');
    }
  }
}())

https://jsfiddle.net/dnLzytju/1/

Please note: It may not be advisable to define your prototype in this manner as it essentially removes all the built-in prototype methods of the object.

If you want to structure your code similarly, you could utilize Object.assign to assist you:

var foo = Object.assign({}, Function.prototype, {
  bar() {
    console.log("Hello!")
  }
});

foo.bar();

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

In ReactJS, the process of rendering a functional component differs from that of a class component

I have a class component that looks like this: import { Component } from 'react'; import { DEFAULT_HPP, DEFAULT_PAGE, DEFAULT_QUERY, PARAM_HPP, PARAM_PAGE, PARAM_SEARCH, PATH_BASE, PATH_SEARCH, } from '../../constants'; ...

What is the method to modify the text of an element without altering its existing properties?

https://i.stack.imgur.com/cBu6P.png $.ajax({ type: "GET", url: "my url" + x, datatype: "html", success: function(data){ //alert(x); //var Content = data; var sendId ; var data = $.parseJSON(data); ...

Preventing request interceptors from altering the request header value in Node.js

I am currently using the http-proxy-middleware to set up a proxy, and it is working smoothly. However, before I apply app.use('/', proxy_options);, I am attempting to intercept my request and update the request header. Unfortunately, the changes ...

Using React hooks to update the state of an array from one component to another

I am currently working on a MERN blog website project and I've encountered an issue while trying to update comments on a post. I'm editing the comment from another component but facing difficulty in updating the state after making changes. Would ...

Sending JSON data back to the server using KeyValuePair in C#

My goal is to send my JSON list back to the POST method (EditCompanyReportField) on the C# server side. The related parameter (fieldSorted) in my method is an array object, but the values are not being passed through. I have a few question marks regarding ...

Increasing the contents of a JavaScript array within a conditional statement

I find myself in a predicament where I need to dynamically add elements to a multidimensional array depending on a specific condition. This means that the type of element to be added will vary based on the condition. if(type == 'text-box'){ ...

Is it permissible to assign the same element as a child to multiple parent elements in jQuery?

Imagine you have the following HTML structure: <div id="first"></div> <div id="second"></div> Now, if you use JavaScript and JQuery to perform the following actions: var $child = $("<span id='child'>Hello</span ...

Retrieving and transforming data from a JSON format using Regular Expressions

Hello there, I have a task that requires extracting data from the token_dict object received through the api and converting it. Here's an example: "token_dict": { "0x13a637026df26f846d55acc52775377717345c06": { "chain&qu ...

Ways to dismiss a Modal popup instantly without having to wait for an ajax response

I am currently facing an issue with sending email attachments through ajax. The process takes too long to send and close the email modal window. I am looking for a solution where the modal window closes immediately after clicking the send email button, all ...

Working with arrays and data to populate tables and cross tables using a single Eloquent Model in Vue and Laravel

There are three tables in the database: species, panel, and a cross table called species_panel. The relationship between them is that one panel can contain multiple species, so a one-to-many relationship is used. Data needs to be inserted into the panel ta ...

Use ajax to add rows to the second-to-last table

I am facing a situation where I have a table with 25 default rows. When scrolling to the bottom of the table, I want to dynamically insert another set of 25 rows. Everything is functioning correctly, but in a specific scenario, I need to preserve the last ...

Implementing Default Language in Next.js 14 for Static Export without URL Prefix: A Step-by-Step Guide

Currently, I am in the process of developing a website using Next.js 14, with the intention of exporting it as a static site for distribution through a CDN (Cloudflare Pages). The website I am working on requires support for internationalization (i18n) to ...

Tips for parsing form values using jQuery AJAX:

Is there a way to extract form values and check if 15 objects have values or not? I attempted to do this using jQuery.parseJSON() but it didn't work as expected. [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Obj ...

"Enhance User Interaction with a Bootstrap Popup when Submitting Form Data via

As a junior web master, I have a simple question to ask. I have created a single page application for a client with a contact form at the end of the page. The validation is done using Bootstrap, but the only method I know to send the form data to a mail id ...

Obtaining only a portion of the text when copying and editing it

I have a React application where I am attempting to copy text from an HTML element, modify it, and then send it back to the user. I have been successful in achieving this, but I am facing an issue where even if I select only a portion of the text, I still ...

retrieve data from jsp page using ajax request

I've coded this JSP snippet Map<String, Long> map = new HashMap<String, Long>(); map.put("A", 10L); map.put("B", 20L); map.put("C", 30L); JSONObject json = new JSONObject(); json.accumulate ...

Encountering an "AJAX not a function" error while using the d3/flask interface

Hey there! I'm new to the world of JavaScript and AJAX. Take a look at this d3 function I've been working on: var node = g.selectAll(".node") .data(root.descendants()) .enter().append("g") .attr("class", function(d) { return "node" + ...

NodeJs backend encounters undefined object due to FormData format request sent from Angular frontend

Never encountered this issue before despite having used this method for a long time. (Angular Frontend) const myFormData = new FormData(); myFormData.append("ok", "true"); this.http.put(my_Express_backend_url, myFormData); (Express ...

Force the page to refresh if the user navigates back using the browser's back button

Similar Question: Cross-browser onload event and the Back button I am looking for a way to automatically refresh a view or page when a user navigates back to it using the browser's back button. Any suggestions? ...

substitute elements within an array using elements from a different array

Looking to swap object(s) in an array with another array while maintaining the original order. Here is arrayOne: [ { "color": "#f8edd1", "selected": true }, { "color": "#d88a ...