Function-calling Context - javascript

I thought the JavaScript, below, would causeobj.fnto run in the context ofentryPoint().
But whenobj.fn()runs, a'locVar is undefined'exception is raised.
function entryPoint () {
var locVar = "xxx";
var obj = {};
PassRcvr(obj);
obj.fn();
}
function PassRcvr(passedObj) { // Being an object, the arg is passed by reference.
passedObj.fn = function () {
alert(locVar);
}
}
The JScript, below, however does run with an awareness oflocVar.
function entryPoint () {
var locVar = "xxx";
var obj = {};
PassRcvr(obj);
obj.fn();
function PassRcvr(passedObj) {
passedObj.fn = function () {
alert(locVar);
}
}
}
Why isn’tobj.fn()aware of the context in which it is called, in both cases, rather than just the one?

The context is the value of this. You aren't using it, so it isn't relevant to your problem.
The scope is not passed. A function keeps the scope it was declared in (that is why we can use closures in JS). Since PassRcvr isn't defined inside entryPoint in the first example, it doesn't have access to variables that are scoped to entryPoint.

In the first case PassRcvr is located in global scope, while the locVar is within entryPoint function's local scope - that is why it cannot be accessed.
In the second case both PassRcvr and locVar are in one local scope.

Related

Till what level do closures keep their execution contexts?

Functions returning from a method keep a copy of their parent execution context, and this is called closure. But what if the function is inside another function which is inside another function like this:
const a = function() {
const aa = 'aa';
return function() {
const bb = 'bb';
return function() {
return aa;
}
}
}
Now, if I call it like:
a()()();
It'll return "aa" because the nexted-most method seems to have access to its grandparent context. So, do all inner methods keep the execution contexts of all their ancestors in which they're nested, when these inner methods are returned?
So, do all inner methods keep the execution contexts of all their ancestors in which they're nested, when these inner methods are returned?
For almost all practical purposes: Yes.
JS engines do optimise though, so in practise only data that needs to be kept around is kept rather than the whole lexical environment.
For example, given:
const a = () => {
const foo = 1;
const bar = 2;
const b = () => {
console.log(foo);
debugger;
}
}
a()();
Most JS engines will make foo available to b but, because b doesn't use bar, they will discard bar and it won't be available to the debugger.
Closure is just a reference to an environment in which a function is defined.
In the code example (I have given each function a name to make it easy to explain):
const a = function() {
const aa = 'aa';
return function b() {
const bb = 'bb';
return function c() {
return aa;
}
}
}
function c will have a reference to the local scope of function b. Similarly, function b will have a reference to the local scope of function a.
This chain of references is what's known as a scope chain and Javascript will traverse this chain until it finds the identifier aa.
Reference to the environment in which a function is defined is saved in an internal slot which the Ecmascript specification calls the [[Environment]] slot of the function object.

Nodejs exporting function that calls non exported function

this is a curiosity type of question.
Assuming a file library.js as follows:
function alpha(){
console.log("in alpha");
beta();
console.log("back in alpha");
}
function beta(){
console.log("in beta")
}
module.exports = {
alpha:alpha
}
When this library is required from another file say main.js then calling the alpha function from this module will look as follows:
var lib = require("library.js")
lib.alpha();
//outputs:
//in alpha
//in beta
//back in alpha
However the beta() function is not really exported. Does this mean NodeJS looks in the library.js file for beta()? If anyone could explain the process in technical detail it would be great.
It depends on the Scope of the function, you can always call functions or variables from the same Scope or all surrounding Scope.
A Scope is usually a function-Statement and it is surrounded by maybe the global Scope (in Browsers the global Scope is window). You can nest functions and the inner functions have access to their own variables as well as the variables of their surrounding Scopes. Take a look at this example:
var varInGlobalScope = 'global'; // This is always accessible
var functionInGlobalNamespace = function () {
// This is accessible inside the function 'functionInGlobalNamespace'
// and all nested functions but not from the global Scope
var varInFunction = 'in function';
var functionInFunction = function () {
// This is accessible inside the function 'functionInFunction'
// but not from 'functionInGlobalNamespace' or the global Scope
var varInFunctionInFunction = 'in function in function';
console.log(varInFunctionInFunction); // works
console.log(varInFunction); // works
console.log(varInGlobalScope); // works
}
console.log(varInFunctionInFunction); // fails
console.log(varInFunction); // works
console.log(varInGlobalScope); // works
}
console.log(varInFunctionInFunction); // fails
console.log(varInFunction); // fails
console.log(varInGlobalScope); // works
This Scope is always there, this means if you build a function as a public member of another function and call a private Member from that it works. But if you are not in the correct Scope it fails. This behaviour is important if you extend the prototypes of an object.
var Demo = function () {
var privateFunction = function () {
console.log('private');
};
this.publicMethod = function () {
console.log('public');
};
this.publicMethodToCallPrivateFunction = function () {
privateFunction();
};
}
Demo.prototype.tryCallingPublicMethod = function () {
this.publicMethod();
};
Demo.prototype.tryCallingPrivateFunction = function () {
privateFunction();
};
var demo = new Demo();
demo.publicMethod(); // works
demo.publicMethodToCallPrivateFunction(); // works
demo.tryCallingPublicMethod(); // works
demo.tryCallingPrivateFunction(); // fails
And now comes the "magic"-part of Node.js because if you build a module to require it in another module or file you have to put all exportable things into the special object module.exports. This is basically a object which is returned by the require function, but as we learned in the examples before the whole Scope of this function is still there.
There are a few other aspects which are maybe important in this handling, but to explain these will bloat the answer.
As a tip you can use this perfectly to implement private functionality and only provide a clean interface to the user. For example to split a huge function into several small chunks to maintain a clean code base.
The reason why this works it because of closure and hoisting.
First of all nodejs creates a surrounding block around the content of a file that looks like this:
(function (exports, require, module, __filename, __dirname) {
function alpha(){
console.log("in alpha");
beta();
console.log("back in alpha");
}
function beta(){
console.log("in beta")
}
module.exports = {
alpha:alpha
}
});
Function declarations are always parsed before the code execution and always hoisted to top. So they are known by each other.
A function Definition like this:
function beta(){
console.log("in beta")
}
can be seen as a shorthand for this:
var beta = function beta(){
console.log("in beta")
}
With the difference that both the declaration and the definition of the function are hoisting to the beginning of the scope.
The resulting code will look this way:
(function (exports, require, module, __filename, __dirname) {
var alpha, beta;
alpha = function alpha(){
console.log("in alpha");
beta();
console.log("back in alpha");
}
beta = function beta(){
console.log("in beta")
}
module.exports = {
alpha:alpha
}
});
Functions which are not exported in the module, works as private method that can not be called from outside. They may only be used if some other function exported use it, else will be inaccessible code.

What way (if any) can I get the reference to anonymous function's closure in javascript?

Let us consider the workable code:
var storage = {};
(function() {
function internalMethod1() { ...; return; }
function internalMethod2() { ...; return; }
storage.storedMethod = internalMethod1;
})();
storage.storedMethod();
Is there any way to call internalMethod2, if it is not called in internalMethod1? In other words, can I access an anonymous closure from outside, if I have access only to one of its functions?
can I access an anonymous closure from outside?
No. Scopes are private in JS, and there's absolutely no way to access them from the outside (unless you use the engine's implementation-specific debugging API…).
Variables (including functions) are only available in the same scope and its children. If you want to access their values outside of the scope, you're at the mercy of the function to expose them in some way (return, assign to global storage variable etc).
No, you cannot access a private, unreferenced scope after it has been executed. You would need to create another closure to create a reference to whatever private method you wanted to expose.
var storage = {};
(function() {
function internalMethod1() {
return {
internalPublic1: internalMethod2
};
}
function internalMethod2() {
console.log('hi');
}
storage.storedMethod = internalMethod1;
})();
var a = storage.storedMethod();
a.internalPublic1(); //'hi'
Try defining IIFE as variable , return reference to internalMethod2 from IIFE
var storage = {};
var method2 = (function() {
function internalMethod1() { console.log(1) };
function internalMethod2() { console.log(2) };
storage.storedMethod = internalMethod1;
return internalMethod2
})();
storage.storedMethod();
method2();

Why nested local function binds `this` to window instead of the parent

I was reading some documentation about javascript and stumbled upon the following code example:
var o = {
value: 1,
outer: function () {
var inner = function () {
console.log(this); //bound to global object
};
inner();
}
};
o.outer();
It outputs window.
I cannot figure out why is the this keyword bound to the global object (window) instead of the parent object (outer).
If you want to access outer from inner's scope, you have to pass the outer's this (which is just like passing outer itself) to its local inner function as an argument. So, as expected:
var o = {
value: 1,
outer: function () {
var inner = function (that) {
console.log(that); //bound to global object
};
inner(this);
}
};
o.outer();
outputs outer.
Isn't it a bit of a nonsense that in outer's scope this is bound to the object itself (i.e. outer), while in the inner's scope, which is local to outer, this is re-bound to the global object (i.e. it overrides outer's binding)?
The ECMAScript specs states that when entering the execution context for function code if the «caller provided thisArg» is either null or undefined, then this is bound to the global object.
But the following:
var o = {
outer: function () {
var inner = function () {
console.log('caller is ' + arguments.callee.caller);
};
inner();
}
}
outputs the object outer itself:
caller is function () {
var inner = function () {
console.log('caller is ' + arguments.callee.caller);
};
inner();
}
On a side, but probably relevant, note:
In strict mode the first code snippet outputs undefined instead of window.
This is because this is set when the function is run, not when it's defined.
For example:
var o = {
func: function(){
console.log(this);
}
};
When you call o.func(), you are doing so in the context o, so it works as expected.
Now let's say you do this:
var f = o.func;
f();
This will not work as expected. This is because when you call f(), it doesn't have any context attached to it, so this will be window.
You can fix this by using .call to change the value of this.
var f = o.func;
f.call(o); // sets `this` to `o` when calling it
That's just how it the language works.
Every time a function is called, this will be reset. In a nested (inner) function it does not inherit the value from the enclosing scope the way other (explicitly declared) variables are.
By default this will be set to window, unless the function is invoked as:
myObj.func(arg1, ...) or
func.call(myObj, arg1, ...) or
func.apply(myObj, [arg1, ...])
in which case this will be equal to myObj
A function called any other way, even if it was originally defined as a property of an object (i.e. var func = myObj.func; func() will use window.
There's also a utility function called .bind which wraps a function reference in such a way that you can provide a specific value which will 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

JS function to return function, shares data which should be private

I'm trying to create a function which returns another function. I want separate information when each of the inner function is run, but this isn't happening. I know that explanation is not great, so I've put together a small example.
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return that;
})(testVal);
}
var a = testFn(4);
var b = testFn(2);
console.log(b.getVal(), a.getVal());
This outputs 2, 2. What I would like is 2, 4 to be output. I know this isn't explained perfectly, so if it's not clear what I'm trying to achieve, can someone explain why the variable seems to be shared across the two functions?
Thanks
Like this ?
var testFn = function(testVal) {
var test = testVal
return {
getVal: function() {
return test
}
}
};
var ab = testFn (4)
var ac = testFn (2)
console.log(ab.getVal(),ac.getVal()) //4 //2
The problem in your code is this.getVal() / returning this
because 'this' refers to the global scope / Window
You are glubbering with the global namespace and overwriting Window.getVal() , the moment you are setting b = testFn (2)
This results in overwriting as method getVal too because they both refer to the global Object and always share the same method getVal
Therefore they share the same closure and are outputing 2
console.log("The same: " + (Window.a === Window.b)) // true
console.log("The same: " + (a === b)) // true
you can see that if you change it a little:
var testFn = function(testVal) {
var x = {}
return (function(testVal) {
var test = testVal;
x.getVal = function () {
return test;
}
return x
})(testVal);
}
var a = testFn(4);
var b = testFn(2);
console.log(b.getVal(), a.getVal());//4 2
it suddenly works because it results in 2 different Objects returned (btw you don't even need the outer closure)
console.log("The same: " + (a === b)) // false
Here are the JSbins First / Second
I hope you understand this, I'm not good in explaining things
If theres anything left unclear, post a comment and I'll try to update the answer
This question comes down to the context in which functions are invoked in JavaScript.
A function that is invoked within another function is executed in the context of the global scope.
In your example, where you have this code:
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return this;
})(testVal);
}
The inner function is being called on the global scope, so this refers to the global object. In JavaScript a function executed within another function is done so with its scope set to the global scope, not the scope of the function it exists within. This tends to trip developers up a fair bit (or at least, it does me!).
For argument's sake, lets presume this is in a browser, so hence this refers to the window object. This is why you get 2 logged twice, because the second time this runs, this.getVal overwrites the getVal method that was defined when you ran var a = testFn(4);.
JavaScript scopes at function level, so every function has its own scope:
var x = 3;
function foo() {
var x = 2;
console.log(x);
};
console.log(x); //gives us 3
foo(); // logs 2
So what you want to do is run that inner function in the context of the testFn function, not in the global scope. You can run a function with a specific context using the call method. I also recorded a screencast on call and apply which discusses this in greater detail. The basic usage of call is:
function foo() {...}.call(this);
That executes foo in the context of this. So, the first step is to make sure your inner function is called in the right context, the context of the testFn method.
var testFn = function(testVal) {
return (function(testVal) {
var test = testVal;
this.getVal = function() {
return test;
}
return this;
}.call(this, testVal);
}
The first parameter to call is the context, and any arguments following that are passed to the function as parameters. So now the inner function is being called in the right scope, it wont add getVal to the global scope, which is a step in the right direction :)
Next though you also need to make sure that every time you call testFn, you do so in a new scope, so you're not overwriting this.getVal when you call testFn for the second time. You can do this using the new keyword. This SO post on the new keyword is well worth reading. When you do var foo = new testFn() you create and execute a new instance of testFN, hereby creating a new scope. This SO question is also relevant.
All you now need to do is change your declaration of a and b to:
var a = new testFn(4);
var b = new testFn(2);
And now console.log(b.getVal(), a.getVal()); will give 2, 4 as desired.
I put a working example on JSBin which should help clear things up. Note how this example defines this.x globally and within the function, and see which ones get logged. Have a play with this and hopefully it might be of use.
The output you get is (2,2) because when you do
var that = this;
what you actually get is the global object (window),
the object that holds all the global methods and variables in your javascript code.
(Note that every variable that is not nested under an object or function is global and
every function that is not nested under an object is global, meaning that functions that are nested under a function are still global)
so, when you set:
var test = testVal;
this.getVal = function() {
return test;
}
you actually set the function "getVal" in the global object, and in the next run you will again set the same function - overriding the first.
To achieve the affect you wanted I would suggest creating and object and returning it in the inner function (as #Glutamat suggested before me):
var testFn = function(testVal) {
return new Object({
getVal: function() {
return testVal;
}
});
}
var a = testFn(4);
var b = testFn(2);
console.log(b.getVal(), a.getVal());
In this way, in the outer function we create an object with an inner function called "getVal" that returns the variable passed to the outer function (testVal).
Here's a JSBin if you want to play around with it
(thanks to #Glutamat for introducing this site, I never heard of it and it's really cool :D)

Categories

Resources