Exploring the bounds of self-invocation functions in JavaScript

Have you ever wondered why self-invocation functions inside another function in JavaScript don't inherit the scope of the outer function?

var prop = "global";

var hash = {
    prop: "hash prop",
    foo: function(){
        console.log(this.prop);
        (function bar(){
            console.log(this.prop);
        })();
    }
};

var literal = {
    prop: "object"
};

hash.foo();
// hash prop
// global

hash.foo.call(literal);
// object
// global

It seems that changing the scope of the outer function does not affect the scope of the inner self-invocation function.

PS: This question delves into the workings of JavaScript and whether all self-executing functions have a 'global' scope by default, and if so, why is this the case?

Answer №1

The issue lies with the this keyword and what it refers to:

foo: function(){
    console.log(this.prop);
    (function bar(){
        console.log(this.prop);  <--- in this context, 'this' refers to the window object
    })();
}

To solve this, you need to store a reference to the outer this:

foo: function(){
    console.log(this.prop);

    var that = this;
    (function bar(){
        console.log(that.prop);  <--- problem solved!
    })();
}

Explanation
The confusion arises from how JavaScript determines the context when a function is invoked.

function Test() {
    this.name = "Test";
    this.bar = function() { console.log("My name is: "+ this.name);}
}

function Blub() {
    this.name = "Blub";
    this.foo = function() { console.log("My name is: " + this.name);}
} 

var a = new Test();
var b = new Blub();

// expected behavior
a.bar(); // My name is: Test
b.foo(); // My name is: Blub

// let's have some fun
a.foo = b.foo; // guess what will happen...

a.foo() // My name is: Test

Wait, why are we still referencing the method of Test? It's actually pointing to the unbound function of Blub.

JavaScript determines the value of this based on the use of . (dots).

When invoking an anonymous function without an object reference (no dot), it defaults this to the global object - which is typically the window object in browsers.

Here's another example where things go awry:

var str = "Hello World";
var ord = str.charCodeAt; // shortcut... but not a good one

ord(0) // no dot... 

Rather than getting char codes from str, we end up with those from the global object, resulting in "[object DOMWindow]".

Answer №2

When you call the inner function without applying any object as the context for this, it defaults to being set to window. If you want the closure to have the same this as the outer function, you can use either of these approaches:

(function bar(){
    console.log(this.prop);
}).call(this);

Or:

var that = this;
(function bar(){
    console.log(that.prop);
})();

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

Unable to fetch data in CakePHP 3.x controller using jQuery AJAX POST

I've been searching everywhere and unfortunately, I can't seem to figure out why the data is not being sent to my controller when posting via ajax. Here's the jQuery code snippet: var newDate = {}; newDate['start' ...

Tips for creating ternary operator logic that account for numerous conditions and optional parameters:

Trying to create a logic for my validator functions that involves using objects as errorMaps for input validation. In the code snippet provided, args.drugName is an optional field. If the user provides text, we want to ensure it is greater than 3 letters; ...

Transmit an unmodifiable array using JSON and Ajax

Is there a way to transmit arrays in a non-editable format? The data I wish to transmit looks like this: var items = []; //console.log(JSON.stringify(items)); allitems = JSON.stringify(items); [{ "assetid": "7814010469", "classid": "1797256701", ...

When the Button is clicked, the component utilizing the Router fails to appear

My current task involves creating a page where users can choose between two options: Button 1 leads to TestOption.js, while Button 2 redirects to TestOption2 (currently using TestOption for testing purposes). The default landing page is SelectionPage. The ...

Steps to turn off fancybox for mobile and show the full image instead

In this scenario... I am seeking a way to deactivate fancybox functionality on mobile devices. I have already discovered one method to disable it... And now I want to directly show the large image in the a href="xxx_large.jpg" instead of using the img src= ...

The ES6 alternative to require() when not using exports

When I utilize require(./filename), I am able to include and run the code within filename without any explicit export being defined inside filename. In ES6, what is the equivalent of this using import ? Appreciate it ...

How can I retrieve the selected items from a Listbox control?

Currently, I am working on an ASP.NET application using C#. One of the features in my project involves a Grid View with a Listbox control. The Listbox is initially set to be disabled by default. My goal is to enable and disable this control dynamically bas ...

Testing the Mongoose save() method by mocking it in an integration test

I am currently facing an issue while trying to create a test scenario. The problem arises with the endpoint I have for a REST-API: Post represents a Mongoose model. router.post('/addPost', (req, res) => { const post = new Post(req.body); ...

Firebug mistakenly detects phantom errors

<div id="video-player" data-src="http://www.youtube.com/embed..."></div> Inspect Element - Browser Developer Tools: Error: Access to property 'toString' denied I scanned the entire page (Ctrl+F) and could not find any reference t ...

Eliminating redundant values from a JSON object that is nested within another

Currently, I am working on rendering a list of Labels from a local JSON file. However, I am facing the issue of duplicates and I want each label to appear only once. I attempted to use Array.filter() and other methods to achieve this line: "Categories": ob ...

Introduce a pause interval between successive ajax get calls

I've created a script that uses an ajax GET request when the user reaches near the end of the page. $(function(){ window.addEventListener('scroll', fetchImages); window.addEventListener('scroll', fetchNotifications); }); ...

What is the method to design a file upload feature without a specific form using JavaScript?

I am currently working on a form that handles file uploads using jQuery and AJAX. The goal is to upload the files individually as JSON containing base64 data. Rather than uploading all the images at once, I want each image to be treated as if it were in it ...

Do multiple AJAX calls share parameters?

I have a JavaScript function as shown below: function makeAjaxCall(outerParameter1, outerParameter2, outerDivId, paramInput){ $.ajax({ type: "POST", url: "some time taking LargeWebMethod or URL", //may take some time to return output dat ...

Storing a collection of items in an array using jQuery

Looking to organize list items from multiple lists of the same class into an array. For example: <ul class="myList"> <li>item 1</li> <li>item 2</li> </ul> <ul class="myList"> <li>i ...

An error was returned by Ajax when attempting to make the ajax call

I have a custom ajax function that successfully updates my database. After the update, I call the successAlert() function. Now, I want to incorporate an error handling mechanism by calling the error function in case of any errors. However, during testing, ...

I'm encountering an issue with this error message: "Warning: Each item in a list must be assigned a unique 'key' prop."

I encountered an error message... Warning: Each child in a list should have a unique "key" prop. I'm puzzled about this because I believe I have assigned a unique key for my map. All the resources I've checked regarding this warning are relat ...

Looking for assistance with converting a basic script into a Joomla 2.5 module and resolving issues with Java integration

I'm having issues with my code in Joomla 2.5. It seems like the Java function is not functioning properly within Joomla. Can someone assist me with troubleshooting this problem? mod_mw_pop_social_traffic.php <?php defined( '_JEXEC' ) or ...

Creating a CSS full-width navigation menu

Recently, I came across a menu code on the web that seemed great. However, I wanted to make my menu responsive and full width. Since I am new to CSS and HTML, adjusting the menu code has been a bit of a challenge for me. .menu, .menu ul { list-style: ...

showcase every value upon submission in the form with options to edit and delete

Is it possible to display all values submitted in a form with edit and delete buttons? Currently, only one value is being displayed at a time. Whenever a new value is displayed, it replaces the old one. How can this be fixed? You can fin ...

Exploring the integration of data from two Firestore collections using JavaScript

I manage two different types of collections, one being called CURRENCY-PAIR and the other Alerts. The collection CURRENCY-PAIR includes the following information: Currency-Pair Name Currency-AskPrice Currency-BidPrice On the other hand, the Alerts colle ...