On what objects are variables within local scope of functions defined on? - javascript

So in this code below, on what object is y defined on? It outputs to three as seen below; of course var y is locally scoped, so I thought of the variable y as scoped to the object s or x. but still gives me undefined.. I know that alert(y) will give me three but that is not my question. I'm wondering on what object it is defined on if it is locally scoped in a function like the code below.
var s = function x() {
var y = 3;
alert(y); // y is defined on what object? //results 3
alert(window.y); //local scope so obviously this won't be true
alert(s.y); //undefined? why //expected 3
alert(x.y); //undefined? why //expexted 3
}
s();

You can think of it like this - every time you call a function, a new anonymous object is created containing all of the local variables of the function.
When you say s.x, it refers to the function s (which is also its own object), but not to the anonymous object from the previous paragraph.. Note how there is only one s function, but it can be called many times, each time creating a new anonymous object.
Here's how your code actually looks* behind the scenes:
var s = function x(_ctx) {
_ctx.y = 3;
alert(_ctx.y); // locals are looked up in _ctx
alert(window.y); //
alert(s.y); // not looking in _ctx, but in s
alert(x.y); // ditto, as x === s
}
s({});
*) well, in a way..

y in declared in the scope of function x. It is not related to any object. s is the same x. It refers to a function. Functions are callable objects which can have it's own properties assigning via s.y or x.y, but everything which is declared in it via var, const, let or function is not related to its object itself, but it's context. So the y is a simple variable, just scoped in the context of the function.

Related

Does top level functions makes closure in JavaScript?

I am learning closure and have basic doubt.
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter = makeCounter();
Here when we are returning function it has closure with outer scope. so it has a closure with count.
var x = 1;
function func() {
console.log(x); // does func has closure with x ??
}
func();
So my question is , only nested function makes closure ??
or top level func has also closure with x ??
Closures in JavaScript are implemented using the [[OuterEnv]] internal field of the [[EnvironmentRecord]] internal field of function declarations. The [[OuterEnv]] value is then copied to the execution context created any time a function is called. This value is then used to create the scope chain, enabling the closure behavior.
Functions declared in the global context are no different in this regard and maintain a link to their surrounding environment, the Global Environment Record.
In the global context, variables declared using var and function declarations behave subtly differently to those declared inside other functions, in that they end up as properties on the global object, but this is an implementation detail.
For the sake of conversation, lets say that every closure creates a "scope" where variables are defined - everything within the closure/scope can access variables, anything outside cannot. With that said, there are two different types of implied closures you should be aware of.
This is not an exhastive description of how closures work, but more of description of the basic practical concepts as they relate to this question. There is much more going on with how call stacks are created, lexical scoping, "global" scope within NodeJS, iframes, sandboxing, var vs const/let, block vs function scopes, and other concepts which I will leave to the reader to discover on their own.
The browser/window/global scope
In the browser, you have the top-level scope (basically window, often referred to as the "global" scope). This kind of acts as a closure in that all "non-enclosed" variables are defined as part of the window scope and are available to most other code running on that page. For example, if you include the following script in the browser, x is part of the global/window scope, whereas y and z are enclosed inside their own nested scopes.
// basic-script.js
// x becomes part of the global/window scope
const x = 10;
(() => {
// y is enclosed in a separate, nested closure
const y = 20;
// x is available in this nested scope/closure
console.log('The sum of x and y is', x + y);
function foo() {
// z is enclosed in a separate, nested closure
const z = 5;
// x and y are both available in this nested scope/closure
console.log('The sum of x y and z is', x + y + z);
}
foo();
// z is not available to the parent scope
console.log(z); //-> undefined
})();
// y is not available to the parent scope
console.log(y); //-> undefined
<script src="basic-script.js"></script>
<script>
// this works because x is not enclosed
console.log('The value of x is', x);
// y and z are not available as they are inside a separate closure
console.log(y, z); //-> undefined, undefined
</script>
JavaScript modules
When you write JavaScript which is imported or required by other modules, every module is automatically wrapped in its own closure. For example, if you were to import/require the above basic-script.js into another JavaScript file, the above would be automatically enclosed like this:
(function() {
var x = 10;
// ... other code removed for brevity
})();
There is some other magic going on for exposing exports and so forth, but that's beyond the scope of this answer (pun intended). If JS modules were not wrapped in their own closure, then you would have a mess of naming collisions and reference issues, as well as a security nightmare.
So to answer your question, yes - your second example shares a closure with "x" - the closure is implicitly created depending on your environment.
Don't know, if you are still searching for the answer or not.
What is you meant by top level, I think you are talking about the global scope. To understand closure one should understand scope better.
And No, Closure in not work in global scope. The main reason of closure is to create a function that return a function with specific variables/calculations with it so that you can reuse that value again. I have a detailed blog in scope, closure and lexical environment. You can check it out https://shimulhsn.hashnode.dev/lexical-environment-and-scope-chain
A practical use of closures is creating a "scope" of protection around variables and functions declared within that function from outside interference. The top scope is "global", accessed using the window variable (an object). Everything, regardless what scope it was declared in, has access to it.
A function declared in global scope creates its own scope that no expression in the global scope and other "sub-global" scopes has access to. Functions declared in the global scope or declared inside other functions create their own scope, that even its immediate parent scope doesn't have access to.
Any variable declared—var, let, const—inside a function block is accessible in that function scope and any sub-scope created within that function scope—i.e., nothing outside that function scope can access it, (except a mechanism the function creating the scope may provide).
The second example in the question, where x is declared in the global scope, means everything has access to x. If x is later changed it is changed in all scopes. x is wide-open to interference anywhere in the code.
var x = 1; <-- declared outside func()
function func() {
// ...etc., etc., etc.
In the first example:
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
...makeCounter() creates a scope that includes count and an anonymous function, and that has access to them. Sub-scopes within this scope also have access to them. However, any expression in the global scope or other sub-global scopes do not have access to them.
Regarding the description that closures give access to an outer function's scope from an inner function—that scope access travels "up", accessing every parent scope, all the way to global scope, regardless how far "down" the "scope-chain" it goes. For example:
const can_i_reach_global = 'yes';
topLevel();
function topLevel () {
console.log('topLevel func, can_i_reach_global:', can_i_reach_global);
oneDeep();
function oneDeep () {
console.log('oneDeep func, can_i_reach_global:', can_i_reach_global);
twoDeep();
function twoDeep () {
console.log('twoDeep func, can_i_reach_global:', can_i_reach_global)
}
}
}
So, as far as practical definitions go, simply stating function closure "...gives you access to an outer function's scope from an inner function..." doesn't describe the usefulness of this programming construct.

The local var does not override the parameter of the same name?

This just blew my mind:
function f(x) {
var x;
console.log(x); // prints 100!
}
f(100);
I always used to think that whenever you declare the local variable, anything with the same name that was declared before becomes hidden behind it. Why var x does not make x undefined as it used to do in other situations?
Compare with this code, which behaves as I used to:
var x = 100;
function f() {
var x;
console.log(x); // prints undefined as expected
}
f();
Both var and the parameter declare the same variable x in the same function scope. When the variable is created, it is initialised to undefined, and shortly after assigned the value 100 that was passed as the argument.
For function code, parameters are also added as bindings to that Environment Record.
The defined parameter x is scooped to the current function. Since x is already been declared in the function, as a parameter, the var x; declaration will be ignored.
For more details: http://es5.github.io/#x10.5
From MDN#var:
Description
...If you re-declare a JavaScript variable, it will not lose its value.
In the first example, since x is already declared within the function f (as an argument), redeclaring it (using var) inside the same function will keep the same value for x before that redeclaration (which is the parameter given to f when it is called).
In the second example, x is declared within the function f. So when looking up x's value to pass on to log we use that x inside f (not the outside one), and since we didn't explicitly give it a value (initializing it), its value is going to be undefined.

Access variable in if block

var func = function () {
var i: number = 0;
if (i == 0) {
var y: number = 1;
}
document.body.innerHTML = y.toString(); // js/ts should complain me in this line
};
func(); // output: 1
As you can see, I've declared variable y inside if block. So, I think it couldn't be referenced outside the scope.
But, when I've tried to run the code, the output is 1.
Is it an issue in typescript/javascript?
Variables in Javascript are hoisted, meaning that var y is moved to the top of the function as if it were declared there.
Initialization, however is not hoisted, so if you change i to be something other than 0, the variable y will still exist, but it will have the value undefined.
This means that the function is exactly equivalent to:
var func = function () {
var i: number = 0;
var y: number;
if (i == 0) {
y = 1;
}
document.body.innerHTML = y.toString(); // js/ts should complain me in this line
};
To get the behavior you expect, you need to use let, which is a part of ECMAScript 2015 (ES6). It is block scoped, as you expect. It will also effectively work so that it is accessible only from the point of definition onwards, which is also probably as you would expect.
If you re-declare a JavaScript variable, it will not lose its value.
The second reference might pave way for a new variable syntax. Actually if you recall variable declaration is not neccessary in javascript. Simpe
y=1;
also works.
The second time when you reference y, outside if block, in my opinion, it tries a re-declaration and retains the old value.
Reference - http://www.w3schools.com/js/js_variables.asp
& http://www.w3schools.com/js/js_scope.asp
Javascript has function scope afaik. Any variable declared within a function, should be accessible from anywhere within the function. So, if you have a function checking if i==0, then you can achieve what you are trying to achieve.
This is as it is supposed to be. Javascript scopes by function, not by block. (This does make it unlike many popular languages)
Variables declared like var myVar = 10; will seep into nested functions but not the other way around. Variables declared like myVar = 10; will go global.
I couldn't find anything which suggested that typescript was any different.
Variables declared inside of an if statement are not scoped to the if statement. They're scoped to the current execution context. There's the Global execution context and then when a function is run, it creates it's own execution context. Inside of your function, you created the variables y and i. It doesn't matter that y was created inside of the if statement, because once it runs, y is created in the scope of the function. So then you do y.toString(), which can access y because it's scoped to the function not the if statement. That's why you get the output of 1. This is not an error, it's by design.

Why can't I access variables inside a function?

If functions are objects in javascript, why can't I access the function scope defined variables?
I understand that in the code:
// variable test assigned an anonymous function
var test = function(){
var x = 5;
};
console.log(test.x); // undefined
// Even when the function is explicitly named:
function test(){
var x = 5;
}
console.log(test.x); // undefined
I don't need to get this working or anything; I just need to understand why functions are like this.
Thanks.
This would be one way to accomplish what you are trying:
function test() {
this.x = 5;
}
var foo = new test();
console.log(foo.x);
Using var x rather than this.x just declares a local variable
I believe it is because those variables only exist within the scope of the function you have defined. Outside the scope of that function they do not exist.
They are the equivalent of private members in a class of an object oriented language.
Alternatively you could have
function test() {
this.x = 5;
}
var testInstance = new test();
console.log(test.x);
Functions are objects, but that doesn't mean that any variable declared inside the function becomes a property of that function object. In fact, that would be terrible because you wouldn't be able to run a function more than once (since the second time, the variables would start with different values).
You can assign a property to a function object like this:
var test = function () {};
test.x = 5
The variable is visible only in the function and it is possible to access it only within the function, you can use global variable and then edot it insode the function.
You have created Local variables. Local variable can only be accessed within the function.
Try to understand about Local & Global JavaScript Variables
Local JavaScript Variables
Variables declared within a JavaScript function, become LOCAL to the function.
Local variables have local scope: They can only be accessed within the function.
function myFunction() {
var name = "roy";
// code here can use name
}
Global JavaScript Variables
A variable declared outside a function, becomes GLOBAL.
A global variable has global scope: All scripts and functions on a web page can access it.
var name = "roy";
// code here can use name
function myFunction() {
// code here can use name
}
var someName = function(){var x ...} /// only has local scope.
What is the scope of variables in JavaScript?
Will describe it better than I can. Good job on being curious and motivated.

OO Javascript : Definitive explanation of variable scope

Can someone provide an explanation of variable scope in JS as it applies to objects, functions and closures?
Global variables
Every variable in Javascript is a named attribute of an object. For example:-
var x = 1;
x is added to the global object. The global object is provided by the script context and may already have a set of attributes. For example in a browser the global object is window. An equivalent to the above line in a browser would be:-
window.x = 1;
Local variables
Now what if we change this to:-
function fn()
{
var x = 1;
}
When fn is called a new object is created called the execution context also referred to as the scope (I use these terms interchangeably). x is added as an attribute to this scope object. Hence each call to fn will get its own instance of a scope object and therefore its own instance of the x attribute attached to that scope object.
Closure
Now lets take this further:-
function fnSequence()
{
var x = 1;
return function() { return x++; }
}
var fn1 = fnSequence();
var fn2 = fnSequence();
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn1())
WScript.Echo(fn1())
WScript.Echo(fn2())
WScript.Echo(fn2())
Note: Replace WScript.Echo with whatever writes to stdout in your context.
The sequence you should get is :-
1 1 2 2 3 4 3 4
So what has happened here? We have fnSequence which initialises a variable x to 1 and returns an anonymous function which will return the value of x and then increment it.
When this function is first executed a scope object is created and an attribute x is added to that scope object with the value of 1. Also created in the same execution object is an anonymous function. Each function object will have a scope attribute which points to the execution context in which it is created. This creates what is know as a scope chain which we will come to later. A reference to this function is returned by fnSequence and stored in fn1.
Note that fn1 is now pointing at the anonymous function and that the anonymous function has a scope attribute pointing at a scope object that still has an x attribute attached. This is known as closure where the contents of an execution context is still reachable after the function it was created for has completed execution.
Now this same sequence happens when assigning to fn2. fn2 will be pointing at a different anonymous function that was created in a different execution context that was create when fnSequence was called this second time.
Scope Chain
What happens when the function held by fn1 is executed the first time? A new execution context is created for the execution of the anonymous function. A return value is to be found from the identifier x. The function's scope object is inspected for an x attribute but none is found. This is where the scope chain comes in. Having failed to find x in the current execution context JavaScript takes the object held by the function's scope attribute and looks for x there. It finds it since the functions scope was created inside an execution of fnSequence, retrieves its value and increments it. Hence 1 is output and the x in this scope is incremented to 2.
Now when fn2 is executed it is ultimately attached to a different execution context whose x attribute is still 1. Hence executing fn2 also results in 1.
As you can see fn1 and fn2 each generate their own independent sequence of numbers.
Variables not declared with var are global in scope.
Functions introduce a scope, but note that if blocks and other blocks do not introduce a scope.
I could also see much information about this by Googling Javascript scope. That's really what I would recommend.
http://www.digital-web.com/articles/scope_in_javascript/
Functions introduce a scope. You can declare functions inside other functions, thereby creating a nested scope. The inner scope can access the outer scope, but the outer can not access the inner scope.
Variables are bound to a scope, using the var keyword. All variables are implicitly bound to the top-level scope. So if you omit the var keyword, you are implicitly referring to a variable bound to the top level. In a browser, the top level is the window object. Note that window is it self a variable, so window == window.window

Categories

Resources