Exploring the reason why nested local function is associated with the window object rather than its parent

While delving into some documentation on javascript, I came across the following code snippet:

var o = {
  value: 1,
  outer: function () {
    var inner = function () {
      console.log(this);  //bound to global object
    };
    inner();
  }
};
o.outer();

This piece of code outputs window.

I'm puzzled as to why the this keyword is bound to the global object (window) rather than the parent object (outer). To access outer from the scope of inner, you need to pass the this of outer (essentially passing outer itself) as an argument. So, this modified snippet:

var o = {
  value: 1,
  outer: function () {
    var inner = function (that) {
      console.log(that);  //bound to global object
    };
    inner(this);
  }
};
o.outer();

now outputs outer.

It seems strange that in the scope of outer, this is linked to the object itself (i.e.

outer</code), but within the local scope of <code>inner
(contained within outer), this shifts back to the global object (effectively overriding outer's binding).


The ECMAScript specifications state that if the «caller provided thisArg» upon entering a function's execution context is either null or undefined, then this is associated with the global object.

However, consider this snippet:

var o = {
    outer: function () {
        var inner = function () {
            console.log('caller is ' + arguments.callee.caller);
        };
        inner();
    }
}

surprisingly outputs the object outer itself:

caller is function () {
    var inner = function () {
        console.log('caller is ' + arguments.callee.caller);
    };
    inner();
}



An additional, yet possibly related, observation:
In strict mode, the initial code snippet yields undefined instead of window.

Answer №1

The reason for this behavior is that the value of this is determined when a function is executed, not when it's defined.

Here's an example to illustrate this concept:

var obj = {
    method: function(){
        console.log(this);
    }
};

When you invoke obj.method(), it runs in the context of obj, so everything behaves as expected.

However, if you try the following:

var fn = obj.method;
fn();

This will not produce the anticipated result because this will be set to the global object (window). This is because fn() is being called without any specific context.

To resolve this issue, you can use the .call method to explicitly specify the value of this:

var fn = obj.method;
fn.call(obj);  // sets `this` to `obj` during invocation

Answer №2

That's just how the language operates.

Each time a function is invoked, this will be reset. In an inner function, it does not inherit the value from the outer scope like other explicitly declared variables do.

By default, this will be set to window, unless the function is called as:

  • myObj.func(arg1, ...) or
  • func.call(myObj, arg1, ...) or
  • func.apply(myObj, [arg1, ...])

In such cases, this will be equal to myObj

If a function is called in any other way, even if it was initially defined as a property of an object (e.g., var func = myObj.func; func()), it will use window.

There is also a useful function called .bind that encapsulates a function reference so that you can specify a particular value to always be used as this:

var myFunc = myObj.func;                // obtain reference to func
var bound = myFunc.bind(someOtherObj);  // bind it to "someOtherObj"

bound();                               // this === someOtherObj
bound.call(myObj)                      // this still === someOtherObj

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

Ways to implement autofocus in Quill Editor with Vue.js

I am currently working with quill and vue 3, but I'm having trouble figuring out how to autofocus the editor input field in their documentation. I have attempted targeting parent elements using: document.getElementById(...).focus() but it didn' ...

Synchronous AJAX calls in jQuery

My system needs to handle up to 180 IO-intensive AJAX jobs on the server side, involving long running SELECT queries. To optimize CPU core usage, I want to transition from executing these AJAX calls sequentially to allowing a maximum of 4 parallel request ...

The response body in Express is returned as a ReadableStream instead of the typical JSON format

When using Express to create an API endpoint, I typically respond with res.json() to send a JSON object in the response that can be consumed by the client. In my API, I am implementing batched promises, resolving them, and sending back an object. However ...

Image loading event doesn't trigger when used inside the useEffect() hook

I am encountering a problem with my React function where the console log message "Drawing image...." does not appear even though I do not see any errors reported from image.onerror. This issue arises when I fetch image data in base64 format fro ...

Tips for implementing a checkbox (with tick/untick functionality) as a replacement for a plus/minus toggle using HTML

Is it possible to use checkboxes instead of plus and minus signs for expanding and collapsing sections? Can the plus and minus symbols be incorporated into the checkbox itself, so that clicking on the checkbox toggles between plus and minus states? Any hel ...

Is it possible to programmatically include a getter method to a class in JavaScript or TypeScript?

My current focus is on TypeScript and I'm exploring the decorators functionality. I would greatly appreciate some guidance or expert knowledge on JavaScript capabilities in this area. I am curious about dynamically adding a getter method to a Prototy ...

Issue with Firefox causing Bootstrap form to appear incorrectly

I recently created a customized form using Bootstrap, but unfortunately, I'm encountering an issue with Firefox. Despite functioning perfectly on other browsers, the radio buttons are being pushed off the edge of the page and aren't displaying pr ...

What is the process of relocating JSON and JS code from within an HTML file to external files?

My goal is to separate JSON and JavaScript code from the HTML file by moving them into external files. The examples shown below were part of a test I conducted to verify that the data was being successfully imported. As I begin to include real data, the J ...

What is the technique for showcasing a collection of <v-img> elements with the v-for directive?

Hey there, hope you're all doing well. I'm curious about how to use the v-for method in Vue js to display a list of images. For example, if I have code that looks like this: <v-flex> <h4>{{$translate('bz_doc_path') ...

Encountering TypeError with Next.js and Firebase: Unable to access properties of undefined (specifically 'apps')

My goal is to create an authentication system using NextJS and Firebase. The issue I am facing is in my firebaseClient.js file, where I am encountering the error "TypeError: Cannot read properties of undefined (reading 'apps')". Here is a snipp ...

How to ensure product images keep their size and aspect ratio in Weebly

Currently, I am running into issues while using Weebly to create an eCommerce website. The problem lies with the product element images - they seem to be appearing twice the size of the original upload. Unfortunately, I do not have access to any other imag ...

Verify whether the input is currently being focused on

My current issue involves an input field that requires a minimum number of characters. If a user begins typing in the field but then switches to another without meeting the character requirement, I would like to change the text color to red. I attempted u ...

Convert the JSON data received from a jQuery AJAX call into a visually appealing HTML table

Utilizing AJAX as the action, I have created a search form. In the success of the AJAX request, I am seeking a way to update a specific div without refreshing the entire page. Below is my form: <?php $properties = array('id' => &ap ...

Display numerous divisions depending on the choices made in several Select2 fields

I need assistance in creating a website without using check-boxes, and I believe jQuery Select2 is the solution. However, I am facing an issue where I cannot display multiple divs based on multiple Select2 selections. For instance, if "OnBase" is selected ...

The Filepond input field is not properly linked to the form data during the sending process

I am having trouble uploading a FilePond file field to the server along with other form elements. My form consists of input fields, a select field, a textarea, and a file input field connected to the Filepond plugin. <form class="uploadform"& ...

Error: Conversion of "2018-01-01-12:12:12:123456" to a date is not possible for the 'DatePipe' filter

<td>{{suite.testSuiteAttributes && suite.testSuiteAttributes.modifiedTimestamp | date: 'yyyy-MM-dd' }} </td> I am trying to display the date in the "05-Feb-2018 11:00:00 PM CST" CST format, but I keep getting an ...

Learn how to effectively transfer data from $.getjson to PHP, specifically through the use of Laravel's @foreach loop

$.getJSON( 'http://localhost/media_books/index.php/new_books.json?provider_id=1&limit=99&offset=1') .done(function( json ) { $(tar).closest('.accordion').children('div').text(json); }); I have successfully obtaine ...

Where should I place an object on an NFT marker using A-Frame and AR.JS?

Struggling to find a solution for aligning the video element correctly within the NFT marker area after exploring AR.JS and AFRAME documentation without success. The issue: The positioning of the video varies on different devices with varying screen and c ...

Is it feasible to utilize express.static twice in Express.js 4.x?

I am seeking to create a unique 404 page that includes HTML, CSS, images, and icons. Upon reviewing my project structure, I have observed that my 404 folder functions correctly when replacing the initial public static homepage. However, I suspect that I ma ...

Testing in NodeJS - revealing the application

Currently, I am in the process of testing my NodeJS application using supertest. To make my app accessible within test.js at the end of app.js, I have exposed it. /////////////////// // https options var options = { key: fs.readFileSync("./private/key ...