A better understanding of javascript precompile - javascript

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.

Related

Does Javascript Use Dynamic Name Resolution?

This is my go to test for whether a language has dynamic name resolution.
function foo() {
function bar() {
print a
}
var a = 10
bar()
}
If the language uses dynamic name resolution, the code should print 10. Otherwise, it should throw an undefined error.
Javascript prints 10. But Javascript uses variable hoisting, which moves var a to the top foo and invalidates my test.
Edit:
If we could delete variables in JS, the following would be an excellent test:
var a = 5
function foo() {
var a = 10
function bar() {
print a
}
delete a
bar()
}
foo()
If JS statically resolves names, bar's a references foo's a. Since foo's a gets deleted (if it were possible), bar would print undefined.
If JS dynamically resolves names, bar's a will be looked up dynamically when bar() is called. Since foo's a is already deleted at this point, the lookup would find the global a, and bar would print 5.
Does Javascript Use Dynamic Name Resolution?
Yes. Consider the following example:
eval("var foo = 'foo';");
console.log(foo);
// > "foo"
The variable foo isn't bound to the lexical environment until runtime (due to the eval() statement), but the fact that no error is thrown (and the code works) demonstrates that the name is resolved dynamically.
But Javascript uses variable hoisting, which moves var a to the top foo and invalidates my test.
Note: maybe you're just saying that hoisting is getting in the way of the test you're trying to perform? If so, please ignore the rest of this answer...
This behavior is actually explained by hoisting, rather than invalidated by it. I.e.,
As you pointed out, due to hoisting, the variable a gets created (but not assigned to, yet) at the very top of the foo() function.
Next, you have a function declaration. As it happens, function declarations get hoisted to the top of their scope, too.
Next you assign the value 10 to a. Note that this happens before you actually invoke bar().
Finally, you actually invoke bar(), at which point a already has been assigned the value 10, resulting in 0 being printed out.
Combining that all together, your foo() function behaves the same as if it had been written as follows:
function foo() {
// hoisted
var a;
// also hoisted
function bar() {
// due to hoisting, `a` is lexically in scope here
console.log(a);
}
// the actual assignment
a = 10
// the invocation
bar()
}
I happened to provide a fairly thorough explanation of the difference between declarations and assignments/initialization in an answer just last night. It explains much of the behavior seen here as well: Declaring vs Initializing a variable?

Unusual javascript behavior

I have encountered a weird behavior in javascript. Consider this code:
var foo;
function bar(){
function foo(){};
foo = 10;
return;
}
foo = 1;
bar();
console.log(foo);
This will output 1. But if I delete the foo function declaration in the third line, it will output 10. Why isn't it output 10 when the function declaration is there? And what is the reason for if I change that function definition to this:
foo = function(){};
it will output 10 again? I know about the hoisting of function declarations, but it doesn't seem to be answer to this.
That's not weird - you have a variable called foo, which you're setting to 1 normally. Inside the bar function, the foo function
if present, shadows this variable
if not present, foo references this original variable.
As such, if you define that foo function, foo=10 will take effect on that, otherwise it will take effect on the original foo.
As for the second part of the question (why does it change back if you use var foo=...), that's because in that case the duplicate variable declaration is merged into one, so you end up with the same as if you didn't write var.
This is a scoping problem. The first foo defined with a var is a "global" variable. When you have the foo function which is also a "variable" inside of the bar function, the foo assignment to 10 will be done to the local scope thus the global foo that you actually print out will not be changed. However, when there is no local foo the assignment inside of bar will change the global variable thus printing 10

Where is the immutable binding record of the identifier in a named function expression stored in JavaScript?

Recently I ran into some interesting facts about named function expressions (NFE). I understand that the function name of an NFE can be accessed within the function body, which makes recursion more convenient and saves us arguments.callee. And the function name is not available outside the function body. For example,
var foo = function bar() {
console.log(typeof bar);
};
typeof foo; // 'function'
typeof bar; // 'undefined', inaccessible outside the NFE
foo(); // 'function', accessible inside the NFE
This is a well-documented feature, and kangax has a wonderful post about NFE and mentioned this phenomenon there. What surprises me most is that the function name of an NFE cannot be re-associated with other values in the function body. For example,
(function foo() {
foo = 5;
alert(foo);
})(); // will alert function code instead of 5
In the above example, We tried to rebind the identifier foo with another value 5. But this fails! And I turned to ES5 Spec and found that an immutable binding record was created and added into the environment records of lexical environment when an NFE is created.
The problem is, when an NFE refers to its own function name inside the function body, the name was resolved as a free variable. In the above example, foo is referred to inside the NFE, but it is neither a formal parameter nor a local variable of this function. So it's a free variable and its binding record can be resolved through the [[scope]] property of the NFE.
So consider this, if we have another identifier with the same name in the outer scope, there seems to be some conflict. For example,
var foo = 1;
(function foo() {
alert(foo);
})(); // will alert function code rather than 1
alert(foo); // 1
When we execute the NFE, the free variable foo was resolved to the function it is associated to. But when the control exits the NFE context, foo was resolved as a local variable in the outer scope.
So my question is as follows:
Where is the immutable binding record of the function name stored?
How come the function name foo outweigh var foo = 1 when resolved inside NFE? Are their binding records stored in the same lexical environment? If so, how?
What's behind the phenomenon that function name foo is accessible inside but invisible outside?
Can someone shed some light on this with ES5 spec? I don't find much discussion online.
Where is the immutable binding record of the function name stored?
In an extra lexical environment record that you cannot see :-)
How come the function name foo outweigh var foo = 1 when resolved inside NFE?
In fact it doesn't. You can declare a new local var foo in the function scope without any collisions, but if you don't then the free foo variable does resolve to the immutable binding. It does outweigh global foo variables higher in the scope chain, however.
var foo = 1;
(function foo() { "use strict";
var foo = 2;
console.log(foo); // 2
}());
(function foo() { "use strict";
console.log(foo); // function …
foo = 2; // Error: Invalid assignment in strict mode
}());
Are their binding records stored in the same lexical environment?
No. Every named function expression is enclosed in an extra lexical environment that has a single, immutable binding for the function's name initialised with the function.
This is described in the Function Definition (§13) section of the spec. While the steps for function declarations and anonymous function expressions basically are "create a new function object with that function body using the current execution context's lexical environment for the Scope", named function expressions are more complicated:
Let funcEnv be the result of calling NewDeclarativeEnvironment passing the running execution context’s Lexical Environment as the argument
Let envRec be funcEnv’s environment record.
Call the CreateImmutableBinding(N) concrete method of envRec passing the Identifier of the function as the argument.
Let closure be the result of creating a new Function object […]. Pass in funcEnv as the Scope.
Call the InitializeImmutableBinding(N,V) concrete method of envRec passing the Identifier of the function and closure as the arguments.
Return closure.
It does construct an extra wrapper environment just for the function expression. In ES6 code with block scopes:
var x = function foo(){};
// is equivalent to
var x;
{
const foo = function() {};
x = foo;
}
// foo is not in scope here
What's behind the phenomenon that function name foo is accessible inside but invisible outside?
The foo immutable binding is not created in the current execution context's lexical environment, but in the wrapper environment which is only used for the closure around the function expression.

Difference in function scope and context

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.

Trying to figure out how scope works

I'm trying to learn JS on codeacademy and I can't understand/get past this thing. Can someone please provide an answer and also an explanation of why is it so? Would deeply appreciate.
// This function tries to set foo to be the
// value specified.
function setFoo(val) {
// foo is declared in a function. It is not
// accessible outside of the function.
var foo = val;
}
setFoo(10);
// Now that we are outside the function, foo is
// not defined and the program will crash! Fix this
// by moving the declaration of foo outside of the
// function. Make sure that setFoo will still update
// the value of foo.
alert(foo);
You can see scope as a term meaning what variables you can reach at a specific "level" in the code. In JavaScript, these "levels" are defined by functions. Each function introduces a new level.
For example, take this sample code:
var a;
// you can access a at this level
function function1() {
var b;
// you can access a, b at this level
function function2() {
var c;
// you can access a, b, c at this level
}
}
So in your case, you should declare var foo; outside the function, preferably above it. Then you can set it inside setFoo with foo = val;. foo then refers to the one you declared in the level above setFoo.
foo is accessible both in setFoo and in the alert call that way; compare it with the above sample code (function1 is setFoo, a is foo and the alert call is in the top-most level. function2, b and c are not used in your case.).
// Create globale variable
// (You should not use globale variables!)
var foo;
// set value
function setFoo(val) {
foo = val;
}
setFoo(10);
// show value
alert(foo);
Just declare foo outside any function then it will be global:
var foo = null;
function setFoo(val) {
foo = val;
}
setFoo(10);
alert(foo);
Try it !
When you declare a variable in Javascript it is only visible to code that is in the same function as it is declared, or a function inernal to that function. Because foo is originally declared in the SetFoo function nothing outside of SetFoo is able to see it, so the call to alert fails as foo does not exist in the gloabl scope.
As the comments suggest, moving the declaration of foo out of the function and into the global scope (which you can think of as a catch-all function that contains everything) would allow you to use foo when calling alert.
var foo;
function setFoo(val) {
foo = val;
}
setFoo(10);
alert(foo); // No longer crashes
Every function in Javascript has it's own scope. That means that every variable you define there with the var keyword, will only be available within that function. That means that when you call setFoo(10), you create the variable foo, give it a value of five, after which it is immediately destroyed because it went out of scope.
There are multiple ways to solve this problem. The first would be to remove the var keyword. This would put foo in the global scope, which means that it's available everywhere. However, this is discouraged, you want to keep the global scope as uncluttered as possible, so that if you have javascript code provided by multiple people on the same page, they can't overwrite other people's variables. Another way to do it would be this:
function setFoo(val){
var foo = val;
alertfoo = function(){
alert(foo)
}
}
In this example, the only thing you're putting in the global scope is the alertfoo function, because you want that to be available everywhere. The alertfoo function is defined inside the setFoo function, this means that although foo should have gone out of scope after setfoo has been executed, it is kept in memory, because alertfoo has access to it.
This makes for some nice tricks. For example, let's say you're making a javascript library that will be included on other people's pages, you'll want to create a scope inside of which you can define variables, without polluting the global scope. The most common way to do this, is by declairing a self-executing function. This is a function which is executed immediately after being defined, it looks like this:
(function(){
//set variables you want to be global in your own code
var mainpage = document.getElementById('main');
//define functions you want to make available to other people in a way that puts them in the global scope
setMainElement = function(newmain){mainpage = newmain;}
})();
You can make this even better by making only one object global, and provide your interfae through the methods of that object, this way, you create a namespace with all the functions that your library contains. The next example uses an object literal to do this. In javascript, you can create an object by putting key/value pairs petween curly braces. the key/value pairs are properties of the object. for example:
(function(){
var privatevar = 10,otherprivate=20;
publicInterface = {
'addToPrivate': function(x){privatevar+=x;},
'getPrivate': function(){return private}
};
})();
Original code:
function setFoo(val) {
var foo = val;
}
setFoo(10);
alert(foo); // Crash!
Their advice to fix the crash:
Fix this by moving the declaration of foo outside of the function
I'm guessing you're confused as to what they mean by "outside of the function".
Try this edited code:
var foo = 5; // "var" declares the variable to be in this outer scope
function setFoo(val) {
foo = val; // but we can still access it in this inner scope...
}
setFoo(10);
alert(foo); // Displays a dialog box that says "10"
Variables defined in the function is valid only in the function
function setFoo(val) {
foo = val;
}
In JavaScript, new scopes are only created by functions

Categories

Resources