Difference in function scope and context - javascript

Does function in javascript have global and local scope?see the code below
function doSomething()
{
function foo()
{
alert(this);
}
foo();
}
foo();
Here function foo() does not get executed. But the "this" keyword within the function points to global window object,if function doSomething() is executed.That means the function foo() is executing on the global scope .since it is executing in global scope why cant we execute the nested function directly without first executing the doSomething().

You're confusing scope and context. The first is fixed for the given function (unless it's returned by some function, effectively being injected into the outer scope), the second (which, among other things, defines what this refers to inside this function) is given to the function when it's invoked - and in fact can be changed with call and apply.
Consider this:
var someObj = function() {
var internalObj = {
nam: 'internal',
doSomething: function() {
console.log('Called from ' + this.name);
}
}
internalObj.doSomething('Internal'); // 1
var someFunc = internalObj.doSomething;
someFunc(); // 2
return {
nam: 'external',
doSomething: internalObj.doSomething
}
}
var x = new someObj();
x.doSomething(); // 3
setTimeout(x.doSomething, 1000); // 4
setTimeout(x.doSomething.bind({nam:'a new one'}), 2000); // 5
JSFiddle.
In this example we define method 'doSomething' as property of internalObj variable, which is local to this constructor function - if you try to access it outside the someObj, you'll get ReferenceError.
When method is called in the constructor function itself (1), you'll get 'Called from internal' logged - as the method's context object (this) refers to internalObj now.
When we assign this method (its reference) to another local variable and call it from there (2), 'undefined' gets logged instead. Scope obviously didn't change here, but context variable did: it refers to the global object now.
Then we return this method as a result of constructor - and things start getting far more interesting: our function is now available in the outer scope! Note, though, the difference between results of its invokations in (3) and (4): the former gives us external (as the context object here is the one that was created by the constructor), the latter, again, return us undefined even though the syntax is the same. ) It happens because functions sent into timeout and event handlers "lose" their context, in short... unless we fix it with Function.prototype.bind method, like in (5).

JavaScript has function level scope.
Any function declaration will be scoped to its nearest containing function automatically.
Function expressions just return a value (that is a function) so you can scope them in any way you choose.
That means the function foo() is executing on the global scope
You are confusing scope and context.
Scope is determined by where a variable is declared (with var or a special rule like "function declarations are scoped"). It effects where a variable is visible.
Context is determined by how a function is called. It effects what the value of this is.
The two are not connected.

Related

Lost context in object

I have this code:
/// global context
function Outer(){
/// Outer context
this.print = function(){
console.log("1: "+this)
inside(); /// "this" is bound to the global object. Why not bound to the Outer object?
function inside(){
console.log("2: "+this)
}
};
}
function print(){
console.log("3: "+this);
}
var obj = new Outer;
obj.print(); /// "this" is bound to the Outer object.
print(); /// "this" is bound to the global object.
Why inside the method call, this has a global object? Can anyone explain this?
That's because, its obeying following 2 JS rules
Rule 1. In Javascript, new function = new scope - that’s the rule.
Rule 2. When a function is called as a method of an object, this is set to the object the method is called on.
Explanation of the code:
For rule 2, this.print() is a feature of Outer object. So this will refer to the Outer object.
So the console.log 1 will print 1: [object Object]
For rule 1, the function inside() in Outer is not a feature of Outer object. So new scope will created and this assigned to window. And that's also same for the last function 'print()'
So console.log 2 will print 2: [object Window]
And console.log 3 will print 3: [object Window] as well
Hope Helps,
Run the code: https://es6console.com/j9bxeati/
Reference: https://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/#function-scope
As the reference states,
In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which do provide their own this binding (it remains the this value of the enclosing lexical context).
<...>
Inside a function, the value of this depends on how the function is called.
<...>
Since the following code is not in strict mode, and because the value of this is not set by the call, this will default to the global object
<...>
So, in strict mode, if this was not defined by the execution context, it remains undefined.
The posted code is not executed in strict mode, so this equals to global variable (window) inside the function when it's called like print().
If this is not the desirable behaviour, and print is expected to be called separately from the object it originally was defined on (e.g. when being passed as a callback), the function can be bound to its lexical this with arrow in ES6:
function Outer(){
this.print = () => { ... };
}
In ES5 bind or self = this recipe can be used:
function Outer(){
this.print = (function(){ ... }).bind(this);
}
function Outer(){
var self = this;
this.print = function(){
self;
...
};
}
If the function isn't expected to be called with another context, it can be called with another context in-place:
print.call(this);
Or:
print.bind(this)();
If it is not obvious for you, that probably means you confuse scope and context of the function.
Scope is what vars function has access to during invocation. Context (this) is determined by how function is invoked.
Now look on how you invoke your function 'inside' and answer the question. Does it vividly owned by any object? That is why you have global
The value of this is determined by how a function is called.
Your "inside" function was called inside "print" function, which has an object reference, but that object did not have "inside" function as a property or that object did not invoke "inside" function.
"this" refers to the object which called it, not the scope in which it is called.
Hence, the global object
the value of this is depends on how you are making a call to the intended function and generally leading parent object plays important role in it.
what does it mean by leading parent object?:
sampleObj.getDetails(); // here 'sampleObj' is the leading parent object for 'getDetails()' function
lets try to clear the things using some examples of making call to the function using below sample code snippet.
function globalFunction(){
console.log('global this: ', this);
}
var simpleObj = {
name : 'john'
};
var complexObj = {
outer: function(){
console.log('outer this: ', this);
}
}
globalFunction(); // will log global object as no leading parent object is available
complexObj.outer(); // will log 'complexObj' object as leading parent object is 'complexObj'
complexObj.outer = complexObj.outer.bind(simpleObj);
complexObj.outer(); // will log 'simpleObj' object as we have set preference as 'simpleObj' for this **
complexObj.outer.call(); // will log global object as we arent setting any preference for 'this' ***
complexObj.outer.call(simpleObj); // will log simpleObj object as we have set preference as simpleObj for 'this' ***
complexObj.outer.apply(); // will log global object as we arent setting any preference for 'this' ****
complexObj.outer.apply(simpleObj); // will log simpleObj object as we have set preference as simpleObj for 'this' ****
hopefully it will help you!
** what is bind: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
*** what is call: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
**** what is apply: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
You can understand it if you read about arrow functions new in ES6.
Until arrow functions, every new function defined its own this value
(a new object in the case of a constructor, undefined in strict mode
function calls, the base object if the function is called as an
"object method", etc.).
Which means that every function defines it's own this and in case of a simple function it will always be a global object and not the context of a function it is defined in. Just for comparison a function which doesn't define it's own this(an arrow function):
/// global context
function Outer(){
/// Outer context
this.print = function(){
console.log("1: "+this)
let inside = () => {
/// "this" is Outer object here
console.log("2: "+this)
}
inside();
};
}

Shadowing `this` - lexical name resolution

EDIT: I think this isn't a duplicate; it being a hidden parameter, I wanted to ask about shadowing in relation to this, and lexical scoping, having read this SO Q/A re. shadowing.
I had thought that the meaning of the name this might be resolved kind of dynamically (in terms of scoping), so as to explain why it doesn't seem to me to be resolved lexically:
function foo() {return this;}
var a = {f: foo};
var b = {f: foo};
a.f() !== b.f();
a.f() !== foo();
a.f() !== window; //not strict mode
But then I read that every function receives this as an additional parameter, silently. (I realise arrow functions are different.)
Obviously helper() doesn't work as we might hope:
ob = {
meth: function(){
var helper = function() {return this;};
return helper();
}
};
ob.meth(); //Window or undefined
As far as I understand, rather than this being resolved by looking at the enclosing scope (the result being ob), instead the interpreter is calling helper() with this set to undefined (strict mode), silently passed as an argument.
So is the surrounding scope's this effectively being shadowed, hence lexical scoping is in fact in action?
You are correct. Except in the case of arrow functions, this is never resolved lexically. It always refers to one of the following:
the object upon which a function was called, such as valueOfThis.foo()
the first argument to apply or call, such as foo.apply(valueOfThis, params) or foo.call(valueOfThis, ...).
the DOM element, in the case of event handlers, such as <button onclick="alert(this.tagName.toLowerCase());"/>
the object being constructed, when a function is used as a constructor, such as Foo = function(){ ... }; new Foo()
the object bound to the function, if the function was created using bind, such as bar = function(){ ... this ...}; foo = bar.bind(valueOfThis); foo()
in a getter/setter, this refers to the object for which the property is being accessed or set, such as valueOfThis.someProperty = 123
window (usually) if none of the above cases, such as foo()
#Bergi provided a great reference for all these in the comments below.
In the case of bound functions, the function being called is actually a different function than was passed to the bind method, because the bind method creates a new function
So is the surrounding scope's this effectively being shadowed, hence lexical scoping is in fact in action?
Yes, one could view it from that perspective. The this bound to the helper scope shadows the one bound to the meth scope. (And if you had used an arrow function, it wouldn't).
However, you still need to remember that this is not an ordinary variable but a special keyword. It is only bound to function scopes, it's not writable, it has weird coerce-to-object semantics in sloppy mode, and it's always implicitly bound - as you say, a hidden parameter.
Unless you're trying to understand how this works in arrow functions (and their lexical resolution), the analogy with scopes and shadowing is pretty useless.

A better understanding of javascript precompile

var foo=1;
function bar(){
foo=10;
return;
function foo(){}
}
bar();
alert(foo);
I am currently learning on how javascript is actually running in the machine and this is a piece of code I see in the example. I got no idea why the final alert is 1 instead of 10. So I am wondering could any one help me explain how the javascript virtual machine is actually execute these code. Thanks!
This is due to function declaration hoisting:
var foo=1;
function bar(){
function foo(){} // This gets moved up here by the engine
foo=10; // You've reassigned the local `foo` function to 10,
// leaving the global `foo` untouched
return;
}
bar();
alert(foo); // Since the foo has never changed in this scope, it's still 1
I got no idea why the final alert is 1 instead of 10.
Because the foo in this line in bar:
foo = 10;
...is the variable-like thing* declared by the function declaration later on in that function:
function foo(){}
...not the foo that's outside bar. That is:
var foo=1;
function bar(){
foo=10; // <== This `foo`
return;
function foo(){} // <== Is the `foo` declared here
}
bar();
alert(foo);
...not to the foo declared in the containing scope (var foo).
There are two reasons that's happening:
Function declarations are processed immediately on entry to the containing scope (the call to bar, in this case), prior to any step-by-step code in the function. This is sometimes called "hoisting" the declarations (because they happen as though they were at the very top). And since the function declaration isn't step-by-step code, the return has no effect on whether it gets processed; it gets processed before the return ever happens.
Function declarations also create what might as well be variables with the names of the functions. So the foo in the function declaration effectively becomes a variable with that name (more below) — and as you've seen in that code, you can assign new values to those "variables."
When you run that code, here's the order of things that the JavaScript engine does:
Creates a variable called foo and gives it the initial value undefined.
Creates the function bar, adding bar as an in-scope symbol (effectively a variable) in the current scope and making it a reference to the bar function.
Starts step-by-step code for that scope.
Assigns the value 1 to foo.
Calls the bar functon.
Creates the foo function relevant to that call to bar, adding foo as an in-scope symbol (effectively a variable) during the call and making it a reference to the function.
Starts the step-by-step code for that scope.
Assigns the value 10 to the local foo (which used to refer to the function).
Returns out of the function.
Calls alert with the foo in that scope, which still has the value 1.
You can read up on all the gory details in §10.4.3 of the spec and the sections it links to.
* "variable-like thing" In JavaScript, each execution context (the global context and any contexts created by calling functions, etc.) has an object that it uses to hold various names used in that context and their values; it's called a "binding object." The binding object for a context (I'm skipping some unrelated details here) has properties for each variable, function declaration, and a few other things like the arguments pseudo-array, the name of the function itself (referring back to the function), and such. The name of the properties are the names of the variables, declared functions, etc. That's why assigning to foo inside bar overwrites the reference to the foo function declared in bar, instead of assigning to the variable in the outer scope. foo is effectively a local variable in bar, even though it's not declared with var, because of the function declaration.
This has to do with a concept called hoisting. function foo is essentially just an alternative syntax for var foo = function .., so inside bar the name foo does not refer to the outer foo variable but to a locally defined foo. This foo is first a function, but later gets overwritten by 10.
Now, through hoisting the name foo is "reserved" and scoped at parse time, before the code executes. Essentially, it executes like this:
function bar(){
var foo = function () {};
foo = 10;
return;
}
Hence it does not overwrite the outer variable at all.

Javascript Scope/Closure: Why can I access internal vars here?

I am currently working on a relatively simple project and discovered something:
var test = (function() {
var internal = 5;
return {
init: function() {
$(document).on('click', function() {
alert(internal);
});
}
};
}());
test.init();
I thought closure and javascript scope (as I understood it) meant that a function can only access its own variables, and those 1 level above it. So Why does this work? When I click on the document I get an alert of "5", I expected to get undefined.
Here is a JSFiddle showing what I'm doing:
http://jsfiddle.net/mcraig_brs/m644L/1/
I thought closure and javascript scope (as I understood it) meant that a function can only access its own variables, and those 1 level above it.
Nope, it's all levels above it. In fact, that's how global variables work in JavaScript; they're just an example of closures in action.
So Why does this work?
When the JavaScript engine needs to resolve a symbol, it looks first (loosely) in the execution context that the symbol appears in (in this case, the one created by the call to the anonymous function you're passing into on). If it doesn't find a matching variable there, it looks at the execution context that surrounds that one (in this case, the one created by calling init). If it doesn't find it there, it looks at the next one out (the one created by calling your outermost anonymous function). And if not there, the next level out, until it reaches the global execution context.
More about closures (on my blog): Closures are not complicated
Note that I kept saying "...created by the call to..." above. This is a critical point: There can be (almost always are) multiple execution contexts created for a given scope as a program runs. Consider:
function foo(name) {
return function() {
alert(name);
};
}
(This is only two levels again, but it applies to as many levels as you like.)
foo, when called, creates and returns a function that, when called, shows us the name that was passed into foo when that function was created:
var f1 = foo("one");
var f2 = foo("two");
f1(); // "one"
f2(); // "two"
Calling foo creates an execution context. The function foo creates has an enduring reference to the part of that context that contains variables for that call (the spec calls it the "variable binding object"). That binding object still exists after foo returns, which is why when we call the function foo creates, it still has access to the relevant name variable.
It's important to remember that it isn't that closures get a copy of the value of the variable. They get an enduring reference to that variable. Which is why this works:
function foo(a) {
return function() {
alert(++a);
};
}
var f = foo(0);
f(); // 1
f(); // 2
f(); // 3
Javascript is statically scoped. when you are writing a function, you will have access to all the variables available to you inside the function as they are available from where you are accessing it.
var a = 10;
function foo() {
// now i have access in a
var b = 20;
// i have access to both a and b
function bar() {
// still have access to both a and b
var c = 30;
// any more nested function will have access to a,b and c
}
}

Scope of this in javascript function

If you have the following code:
var global = this;
function A () {
function B () {
return this;
}
return B();
}
var C = new A();
C === global // true
Why does the this in function B refer to the global space and not the this of the object A?
The value of this is determined upon every function call. Because B is called without any context, the value of this is the global object.
It's possible to preserve this in an outer context by simply copying it:
function A() {
var x = this;
function B() {
return x;
}
return B();
}
this has nothing to do with scope, it's not a variable. It's a keyword that evaluates to the currently executing function's object context. The function's object context is determined by how you call it. It doesn't matter where or how the function is defined.
When you call a function like fn() then it is not in object context and the language wrongly attempts to work around it when it should just throw an error at the mere sight of this. This is somewhat fixed in strict mode where it would evaluate to undefined.
When you call a function as a property of some object I.E. obj.fn() then obj is bound to this for that call.
Since it would be clunky having to attach a function to some object just to get the right object context for the call, all functions inherit a .call method that allows you to specify the object context explicitly:
return B.call(this);
To accompany Pointy's correct answer:
The reasoning for this is because you can do whatever you want with functions.
You can return function B from function A, and save it as a global variable.
Or you could append function B as a method to an Object, or a dozen objects.
Or you could use it in an AJAX callback, or use it as a callback from a timer.
Because the engine doesn't know what's going to happen with function B, the language says that this refers to whatever the function is being called on, at the time it's called.
This adds a lot of dynamism to the language, but it also adds a lot of headache, if you're not sure what "this" is pointing to at any given time.
Rule of thumb:
If the function is directly attached as the method of an object, or a function is being called with .call or .apply and being fed a context, like myFunc.call(myObj), then this refers to window.

Categories

Resources