Why is it that methods lose their binding when they are returned from a ternary operator?

class TestClass {
    constructor() {
        this.prop = 5;
    }
    MethA() {
        console.log(this);
        console.log(this.prop);
    }
    MethB() {
        (true ? this.MethA : null)();
    }
}
Test = new TestClass();
Test.MethB();

What is the reason for the failure of this code when trying to access this.prop in MethA from the ternary operator in MethB?

VM:6 undefined
VM:7 Uncaught TypeError: Cannot read property 'prop' of undefined
    at MethA (<anonymous>:7:26)
    at TestClass.MethB (<anonymous>:10:35)
    at <anonymous>:14:6

To address any potential comments regarding the inclusion of null in this illustrative example:

In actual code, the condition of the ternary operator is a variable flag, with the false value being another method. This structure allows two functions to share a common argument list that only needs to be written once and doesn't require a name.

No, moving the calls inside the ternary operator does not fully resolve this issue. It sacrifices the benefits of writing arguments only once and may lead to side effects.

The true solution would involve replacing the ternary operation with an if {} else {} for side effect purposes or wrapping the methods in arrow functions for a value expression. However, neither of these solutions fully addresses the root cause of why this code fails to work due to underlying language quirks.

Answer №1

JavaScript's way of handling scope is crucial in understanding how the value of `this` is determined.

The key concept to grasp is that when a function is called, `this` typically refers to the object on which the method was invoked.

wookie.eatBanana(); // within eatBanana, this points to wookie

However, if the method is called separately from the object, `this` becomes `undefined`:

const detachedFn = wookie.eatBanana;

// same function, but now this is undefined
detachedFn(); 

By using `this.MethA` within the ternary operation, you are essentially removing it from its original context. It's like doing this:

MethB() {
  const method = true ? this.MethA : null;
  method(); // when executed independently, 'this' inside MethA is undefined
}

If this behavior is not desired, there are various solutions available.

Arrow functions inherit the current scope, so converting MethA into an arrow function resolves this issue:

MethA = () => {
  console.log(this);
  console.log(this.prop);
}

const method = this.MethA;
method(); // this works as expected because arrow functions retain their enclosing scope

Alternatively, you can use methods like bind, call, or apply to explicitly specify the desired scope:

const method = this.MethA.bind(this); // create a new function bound to 'this'
MethA.call(this); // call with a specific context
MethA.apply(this); // similar to call but handles arguments differently

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

Difficulty encountered when deploying cloud function related to processing a stripe payment intent

I've been troubleshooting this code and trying to deploy it on Firebase, but I keep running into a CORS policy error: "Access to fetch at ... from origin ... has been blocked by CORS policy." Despite following Google's documentation on addressin ...

Error in MEAN Stack: Unable to access the property 'companyTitle' because it is undefined

I have established a MongoDB collection named joblist in my database. Additionally, I have developed a DB schema known as jobList.js. var mongoose = require('mongoose'); const joblistSchema = mongoose.Schema({ companyTitle: String, jobT ...

Creating a Mongoose schema to store an array of objects, where updates will automatically add new objects

const mongoose = require('mongoose'); module.exports = mongoose.model('GridModel', { Request_Id : { type : Number, required : true }, viewStudents : { type : Array , default : [] } }); The mongoose model above needs to b ...

Execute a function upon pressing the enter key

Currently, I am working on coding a webpage with a form that includes one field where users input a set of numbers. After typing in the numbers, they should then press a button labeled 'Run' to execute the code. However, the issue arises when use ...

To ascertain whether the mouse is still lingering over the menu

I have a condensed menu construction that unfortunately cannot be changed in HTML, only CSS and JS modifications are possible! $('span').on("hover", handleHover('span')); function handleHover(e) { $(e).on({ mouse ...

step-by-step guide on transferring the text content of an HTML paragraph element to another HTML paragraph element through JavaScript in ASP.NET

I'm looking for help with passing the text value from one HTML paragraph element to another when a JavaScript function is called. The function loads a div element with an enlarged image and a paragraph content. Below is the code I am using: JavaScrip ...

Show a separate div in a block format if the data field contains a value

<span>{{pstCtrl.doctorProfile.boardCertification ? === 'Yes' : $yes.display-block}}</span> <span class="yes">Yes</span> span.yes { display:none; } In my Angular.JS project, the code snippet above is demonstra ...

What is the name attribute of an ES2015 function?

var individual = { announceIdentity() { console.log(this.identity); }, get firstID() { return "Superman"; } }; individual.announceIdentity.identification // "identity" individual.firstID.identifier // "get firstID" I recently came acros ...

The map function is not functioning properly following a state update in React

Hey there! I've come across a bit of a dilemma with my map function that I'm using to map a data array within one of the states in my application. Everything seems to be running smoothly upon the initial load, but as soon as I start adding new d ...

Unable to display the value of my array in JSON encoded PHP due to it being undefined

In my cart.php file, I have encoded an array to JSON and returned it to an AJAX function: $data = array(); $data['total'] = '10000'; $data['quantity'] = '10'; echo json_encode($data); In my index.php f ...

What is the best way to prioritize a non-submit button over a submit button in material-ui?

I am facing an issue with a form on my website. Whenever I press the enter key, the form is automatically submitted. Everything seems to be working fine so far. However, there is a specific scenario where if a user selects a certain option in the form, it ...

Adding a unique key to every element within a JavaScript array

I am working with the array provided below which contains simple values. My goal is to add a key id before each value in the array, resulting in something like this: ["id:a", "id:b","id:c","id:d"]. Is there an easy way to achieve this? Any assistance would ...

Vuejs may encounter challenges with v-model when numerous items are present on the page

My simple page consists of a form at the top for submitting data and a list below that, as shown in the image: https://i.sstatic.net/3WjY2.png The list is populated with data from an api, each object having only 4 properties. Currently, there are a total ...

Retrieving data arrays from response.json

I've been on a wild goose chase trying to solve this puzzling issue. RAWG has transitioned to using their own API instead of Rapid API for game reviews, and I'm in need of data for "Tom Clancy Rainbow Six Siege". Despite my efforts to convert t ...

Can anyone explain how to successfully implement AJAX data in a PHP file?

I've been struggling to transfer data from my JavaScript file to a PHP variable. I've spent hours searching for solutions, but none seem to apply to my unique code. Here's the JavaScript code I'm working with... $(function(){ ...

What is the best way to showcase a collapsible tree using AngularJS and Bootstrap?

I'm currently working on a web application that requires the display of a tree structure using lists. Here is the basic outline: * Node 1 * Node 1.1 * Node 1.1.1 * Node 1.1.1.1 * Node 1.1.2 * Node 1.2 http://jsfid ...

Appending a row to a table will not trigger events in Select2

Despite several attempts, I can't seem to get the select2:select event working on dynamically added rows in a table using select2. The event only works on the original row. Unfortunately, I don't have any additional details about this issue. COD ...

What is the best way to eliminate transition effects in Vue.js when there are changes in the data

My Vue.js 2.x component fetches data from the server in this way. <template> ... <a href="..." v-if="data.status !== 'blind'">Link</a> ... </template> <script> export default { ... data: { retu ...

Mastering React Final Form: Displaying data using a button placed outside the form

I have a query regarding integrating my form component (<InvoiceForm.tsx />) with a button component (<Button.js />) to save its data in the database. The button component is located in another component called <InvoiceList.tsx />, which ...

Can anyone suggest a node.js equivalent for XMLHttpRequest.readyState in http?

One important feature of Javascript's XMLHttpRequest object is the readyState property. This property, often used alongside response codes, allows developers to determine if an HTTP request has completed before proceeding with additional code. if (th ...