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

What is the best way to convert my query for use with MongoDB in a Node.js application?

Here is the structure of my MongoDB query: db.test.findOne({"User.David":{$elemMatch:{"action":"todo","status":"Done"}}}) I am currently developing a node.js API that allows users to retrieve documents based on username and status. Below is my attempt a ...

Issue with setting innerHTML of element in AngularJS app upon ng-click event

Look at this block of HTML: <div class="custom-select"> <div class="custom-select-placeholder"> <span id="placeholder-pages">Display all items</span> </div> <ul class="custom-select- ...

Error: Unable to access the 'resource' property as it is undefined

I am currently working on a project that involves fetching the latest 4 results from Craigslist using a query. Although I have successfully retrieved all the relevant information, I seem to be encountering an issue with loading the URL of the image from th ...

Is there a way for me to send a URL request from my website to a different server using PHP?

I am looking to initiate a request from my website to my server using a specific IP address. From there, I need the server to send another request to a different server and then display the response on the webpage. Can anyone provide guidance on how to ...

Tips for preventing click events from interfering with execution in React

On my screen, there is a specific image I am looking to prevent all actions while a process is running. When I trigger the Execute button, it initiates an API call that can take 4-5 minutes to complete. During this time, I need to restrict user interacti ...

Investigating Javascript compatibility problems with Firefox 4

In FF3.X and IE7 to 9, the code below is functioning correctly, but in FF4, there seems to be an issue. The following code is used in two different locations within my file: var args = "method=getoptions"; args += "&dr ...

Trigger the next button click event using jQuery

Is it possible to implement a slideshow on my website where clicking a button displays the relevant slide? My goal is to incorporate a timer that will automatically click the next button after 3 seconds, enabling the slideshow to transition automatically. ...

I need to extract information from the database and save all entries from the form in order to send them to myself. This includes calculating the real-time multiplication of weight and pieces

For a project, I need to gather contact data from the client, and then populate a MySQL database with the information to create new rows in a table. There's an additional requirement where I have to calculate the total weight of element pieces multip ...

extract information from a document and store it in an array

As I delve into the realm of programming, I find myself grappling with the best approach to extract data from a file and store it in an array. My ultimate aim is to establish a dictionary for a game that can verify words provided by players. Despite my no ...

Using JavaScript to Set Values and Manage Session State in APEX

Trying to utilize JavaScript in Oracle APEX to set the value and session state. See below function that is being called: function updateItemValue(element) { $s('P2020_SELECTED', element); apex.server.process ('MY_PROCESS', { ...

Query about Javascript/Node/JSON - why isn't this functioning properly?

I thought I had a good grasp on what I was doing until the process started getting jumbled. My code is being executed through Node, not a web browser. For some reason, it jumps to the prompt at the end of the while loop first and I'm not sure why tha ...

issue with scrolling using the ideal scrollbar

Can someone help me figure out how to integrate the 'perfectScrollbar('update')' function with my Angular.js code? $http.get('demo/json/test.json'). success(function(data, status, headers, config) { $scope.items = d ...

Dealing with Unwanted Keys When Parsing JSON Objects

Struggling with parsing a list of Objects, for example: After running the code JSON.parse("[{},{},{},{},{}]"); The result is as follows: 0: Object 1: Object 2: Object 3: Object 4: Object 5: Object Expecting an array of 5 objects like this: [Object,Ob ...

Is it possible to obtain the output of a JavaScript file directly? (kind of like AJAX)

My previous experience with AJAX involved a server-side language like PHP generating xHTML with attached JS. The JS would then query another file using parameters set in either GET or POST. The output of the queried file would be returned to the JS, which ...

Chrome debugging tool does not refresh page source

This issue has been lingering for quite some time and despite similar questions, I have not come across a satisfactory solution. The problem lies in the fact that the SOURCE used to step through the code does not refresh with every page load. Disabling the ...

"Troubleshooting: Difficulty with hover function in jqgrid not functioning on colored rows

My JQGrid setup includes the following: <table id="grid"></table> var data = [[48803, "DSK1", "", "02200220", "OPEN"], [48769, "APPR", "", "77733337", "ENTERED"]]; $("#grid").jqGrid({ datatype: "local", height: 250, colNa ...

Using a combination of different materials on a single mesh can lead to problems with z-index and clipping

Currently in my threejs project, I am attempting to apply two different materials to a mesh. One material has a solid color, while the other has a canvas texture. To achieve this, I have created both materials and added them to an array, which is then assi ...

Update the var value based on the specific image being switched using jQuery

I have implemented a jQuery function that successfully swaps images when clicked. However, I am now looking to enhance this functionality by passing a parameter using $.get depending on the image being displayed. Here is the scenario: I have multiple comm ...

Sorting Tables through the Power of Drag and Drop

While utilizing both the Jquery Tablesorter plugin and the Drag and Drop plugin together, everything seems to be functioning correctly. However, when attempting to use the serialize function of the tableDnD, an error message stating "empty string getElemen ...

Vue JS encountering Slack API CORS issue while using axios

I am currently developing an application using Capacitor JS & Nuxt JS to interact with the Slack API for setting my Slack status. I have successfully created a Slack App and obtained a xoxp- token, which works perfectly when sending a POST request via Post ...