Today I had a discussion with a colleague about nested functions in Javascript:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
d = 'Bound to global object.'
}
In this example, trials point out that b is not reachable outside the body of a, much like c is. However, d is - after executing a(). Looking for the exact definition of this behaviour in the ECMAScript v.3 standard , I didn't find the exact wording I was looking for; what Sec.13 p.71 does not say, is which object the function object created by the function declaration statement is to be bound to. Am I missing something?
This is static scoping. Statements within a function are scoped within that function.
Javascript has a quirky behavior, however, which is that without the var keyword, you've implied a global variable. That's what you're seeing in your test. Your "d" variable is available because it is an implied global, despite being written within the body of a function.
Also, to answer the second part of your question: A function exists in whatever scope it is declared, just like a variable.
Sidenote:
You probably don't want global variables, especially not implied ones. It's recommended that you always use the var keyword, to prevent confusion and to keep everything clean.
Sidenote:
The ECMA Standard isn't probably the most helpful place to find answers about Javascript, although it certainly isn't a bad resource. Remember that javascript in your browser is just an implementation of that standard, so the standards document will be giving you the rules that were (mostly) followed by the implementors when the javascript engine was being built. It can't offer specific information about the implementations you care about, namely the major browsers. There are a couple of books in particular which will give you very direct information about how the javascript implementations in the major browsers behave. To illustrate the difference, I'll include excerpts below from both the ECMAScript specification, and a book on Javascript. I think you'll agree that the book gives a more direct answer.
Here's from the ECMAScript Language Specification:
10.2 Entering An Execution Context
Every function and constructor call
enters a new execution context, even
if a function is calling itself
recursively. Every return exits an
execution context. A thrown exception,
if not caught, may also exit one or
more execution contexts.
When control
enters an execution context, the scope
chain is created and initialised,
variable instantiation is performed,
and the this value is determined.
The
initialisation of the scope chain,
variable instantiation, and the
determination of the this value depend
on the type of code being entered.
Here's from O'Reilly's Javascript: The Definitive Guide (5th Edition):
8.8.1 Lexical Scoping
Functions in JavaScript are lexically
rather than dynamically scoped. This
means that they run in the scope in
which they are defined, not the scope
from which they are executed. When a
function is defined, the current scope
chain is saved and becomes part of
the internal state of the function.
...
Highly recommended for covering these kinds of questions is Douglas Crockford's book:
JavaScript, The Good Parts http://oreilly.com/catalog/covers/9780596517748_cat.gif
Javascript, The Good Parts, also from O'Reilly.
As I understand it, these are equivalent as far as scoping is concerned:
function a() { ... }
and
var a = function() { ... }
It seems important to note that while d is being created as a "global", it is in reality being created as a property of the window object. This means that you could inadvertently be overwriting something that already exists on the window object or your variable might actually fail to be created at all. So:
function a() {
d = 'Hello World';
}
alert(window.d); // shows 'Hello World'
But you cannot do:
function a() {
document = 'something';
}
because you cannot overwrite the window.document object.
For all practical purposes you can imaging that all of your code is running in a giant with(window) block.
Javascript has two scopes. Global, and functional. If you declare a variable inside a function using the "var" keyword, it will be local to that function, and any inner functions. If you declare a variable outside of a function, it has global scope.
Finally, if you omit the var keyword when first declaring a variable, javascript assumes you wanted a global variable, no matter where you declare it.
So, you're calling function a, and function a is declaring a global variable d.
...
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
d = 'Bound to global object.'
}
without being preceded by var, d is global. Do this to made d private:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
var d = 'Bound to local object.'
}
Related
I have two questions about hoisting:
The way function declarations are hoisted is that they go to the very top, even above variable declarations, to my understanding.
If we have this code:
function fn() {
callback();
}
function callback() {
console.log('why does this show');
}
I don't understand how this works, since both functions are hoisted to the top (which effectively produces the same code that already exists). But callback is still created below fn, and I don't see why we can access it in fn. My guess is it has something to do with the top level objects being able to access each other regardless of lexical position.
Similarly:
var a = 10;
function fn() {
console.log(a);
}
fn();
How does this work? Because the way I understand hoisting makes it seem like the function should be hoisted even above var a, which makes it seem like variables should always be inaccessible in functions.
We can go down the rabbit hole with this but I want to try to give a brief explanation on how your examples work.
Whenever the JavaScript engine creates an execution context (also known as calling stack) whether through functions or code in the global scope it creates an lexical environment. Which is a data structure that holds a collection of name/value pairs about variables and functions in it's own scope or from it's parent scope by using a reference.
About your first example. Both functions get added to the global execution context. If you call fn() in your first example initially. It will then add callback() to the call stack of fn() and execute it accordingly. So, the order of your functions don't really matter in this case.
You're second example is a different case. The execution context knowns you are referring to the global variable and therefor adding a reference to the lexical environment and that makes it able to use the variable inside fn().
This can be quite hard to get a grasp of. There are a ton of resources related to hoisting, scopes, lexical environments and execution contexts so be sure to check those out. :)
This is because how our Javascript Engine parse and compile the code.
I'm not an expert but V8 (The Chorme Engine for JS) in the first file get all the variables and functions names and store all the function references. So, you can "use" a function before "declare" because JS know where the function is.
Some languages, even C++ you could do that and is a nice feature :)
As we know, traditionally JS has been lacking block scope. As we know JS has had only function scope up until recently.
In recent versions of JS though, we can have let and const variables which are visible only in the scope where they are defined.
But... deep down... how is this done/implemented really? Is there really now in the language a first-class notion of block scope in JS, or is the block scope thing just some simulation to make certain variables visible only in the block where they are defined?
I mean is block scope in recent JS versions a first-class thing, just like function scope is, or is block scope just some sort of simulation while we actually still have just the old good function scope?
But... deep down... how is this done/implemented really? Is there really now in the language a first-class notion of block scope in JS...?
Yes, there is. A new block¹ creates a new lexical environment in the same way that creating a function does (without, obviously, all the other aspects of creating a function). You can see that in the Evaluation section of blocks in the spec.
It's a first-class language construct.
¹ I originally wrote "...containing a let, const, or class declaration..." but the specification doesn't actually make that distinction, though I expect JavaScript engines do (since there's no need for a new environment if there are no lexically-declared bindings).
In a comment you've asked:
What about hoisting? I read that block scoped-variables are hoisted to the top of the block they are defined in... but then also... You get an error if you try to access a block-scoped variable before the line/statement where it is declared in its block? This sounds contradictory, no? If they are hoisted we would not be getting this error but we would be getting undefined. What is the truth here?
In my book I describe them as half-hoisted: The creation of the variable (more generally, the "binding") is hoisted to the top of the scope in which its declaration (let x or whatever) appears (the block, in this case), but the binding isn't initialized until the declaration is reached in the step-by-step execution of the code. The time between creation and initialization is called the Temporal Dead Zone. You can't use the binding (at all) within the TDZ.
This only applies to let, const, and class declarations. var is handled differently in two ways: 1. Obviously, var is hoisted to the top of the function (or global) scope, not just block scope. 2. Less obviously, var bindings are both created and initialized (with the value undefined) upon entry to the scope. They're fully hoisted. (The declaration of them is; any initializer on the var statement is actually an assignment, and done when that statement is reached in the step-by-step execution of the code.)
Here's an example:
function foo(n) {
// `l1` and `l2` don't exist here at all here
// `v` is created and initialized with `undefined` here, so we can happily
// do this:
console.log(`v = ${v}`);
if (n > 10) {
// `l1` and `l2` are created here but not initialized; if we tried to
// use them here, we'd get an error; uncomment this line to see it:
// console.log(`l1 = ${l1}`);
console.log("n is > 10");
var v = "a"; // `v` is assigned the value `"a"` here, replacing the
// value `undefined`
let l1 = "b"; // `l1` is initialized with the value `"b"` here
console.log(`l1 = ${l1}`);
let l2; // `l2` is initialized with the value `undefined `here
console.log(`l2 = ${l2}`);
l2 = "c"; // `l2` is assigned the value `"c"` here, replacing the
// value `undefined`
console.log(`l2 = ${l2}`);
}
}
foo(20);
Just for completeness, function declarations are also fully-hoisted, but even more so than var: The function is actually created and assigned to the binding upon entry to the scope (unlike var, which gets the value undefined).
In a comment you've observed:
Then... I don't see what's the difference between no hoisting and half-hoisting...
Good point, I didn't explain that. The difference relates to shadowing identifiers in the outer scope. Consider:
function foo() {
let a = 1;
if (/*...*/) {
console.log(`a = ${a}`);
let a = 2;
// ...
}
}
What should the log show?
Sorry, that was a trick question; the log doesn't show anything, because you get an error trying to use a there, because the inner a declaration shadows (hides) the outer a declaration, but the inner a isn't initialized yet, so you can't use it yet. It's in the TDZ.
It would have been possible to make the outer a accessible there, or to make the inner a accessible there with the value undefined (e.g., fully hoisting it like var, but just within the block), but both of those have problems the TDZ helps solve. (Specifically: Using the outer a would have been confusing for programmers [a means one thing at the beginning of the block but something else later?!] and would have meant JavaScript engines had to create new lexical environments all over the place, basically every let or const or class would introduce a new one. And pre-initializing with undefined is confusing for programmers, as var has shown us over the years...)
Reading Kyle Simpson's You Don't Know JS: Scopes & Closures, he argues that you should stay away from both the eval() function and the with keyword because whenever the compiler sees these 2 (i'm paraphrasing), it doesn't perform some optimizations related to lexical-scope and storing the location of identifiers because these keywords could potentially modify the lexical scope therefore making the compiler's optimizations sort of incorrect (i am assuming that the optimizations are something like the compiler storing the location of each identifier so it can provide an identifier's value without searching for it when it is requested during runtime).
Now I understand why that would happen when you used the eval() keyword: your eval could be evaluating user input, and that user input could be the declaration of a new variable, which shadows another variable that you are accessing later in let's say the function that is executing, if the compiler had stored the static location, the access would return the value of the wrong identifier (since the access should have returned the value of the identifier that was declared by eval(), but it returned the value of the variable that was stored by the compiler to optimize the look-ups). So I am just assuming this is why the compiler doesn't perform its scope-related look-ups whenever it spots an eval() in your code.
But why does the compiler do the same thing for the with keyword ? The book says that it does so because with creates a new lexical scope during runtime and it uses the properties of the object passed as the argument to with to declare some new identifiers. I literally have no idea what this means and i have a very hard time trying to visualize all this since it is all the compiler-related stuff in this book is all theory.
I know that i could be on the wrong track, in that case, please kindly correct all my misunderstandings :)
The optimization referred to here is based on this fact: the variables declared within a function can always be determined via simple static analysis of the code (i.e., by looking at var/let and function declarations), and the set of declared variables within a function never changes.
eval violates this assumption by introducing the ability to mutate a local binding (by introducing new variables to a function's scope at run time). with violates this assumption by introducing a new non-lexical binding within a function whose properties are computed at runtime. Static code analysis cannot always determine the properties of a with object, so the analyzer cannot determine what variables exist within a with block. Importantly, the object supplied to with may change between executions of the function, meaning that the set of variables within that lexical section of the function can never be guaranteed to be consistent.
Consider the simple function:
function foo() {
var a, b;
function c() { ... }
...
}
All points in foo have three locally-scope variables, a, b and c. An optimizer can attach a permanent kind of "note" to the function that says, "This function has three variables: a, b, and c. This will never change."
Now consider:
function bar(egg) {
var a, b;
function c() { ... }
with(egg) {
...
}
}
In the with block, there is no knowing what variables will or won't exist. If there is an a, b or c in the with, we don't know until run time if that refers to a variable of bar or one created by the with(egg) lexical scope.
To show a semi-practical example of how this is a problem, finally consider:
function baz(egg) {
with(egg) {
return function() { return whereami; }
}
}
When the inner function executes (e.g., bar({...})()), the execution engine will look up the scope chain to find whereami. If the optimizer had been allowed to attach a permanent scope-note to baz, then the execution engine would immediately know look in the function's baz closure for the value of whereami, because that would be guaranteed to be the home of whereami (any similarly-named variable up the scope chain would be shadowed by the closest one). However, it doesn't know if whereami exists in baz or not, because it could be conditionally created by the contents of egg on the particular run of bar that created that inner function. Therefore, it has to check, and the optimization is not used.
Take this example:
{
let a = 1; //stored at 123
{
let b = 2; //stored at 124
console.log(a/*123*/,b/*124*/);
}
}
And now this:
{
let a = 1;//stored at 123
with({a:3}){
console.log(a /*123 ??*/);
}
}
I've been doing some javascript reading, and I've gathered that a closure has access only to the closure "wrapping" it, or, you might say it's immediate parent. Now I've been playing a bit, and I see in this jsfiddle that even deep nested functions have access to to vars defined way up.
Can anyone please explain that? Or explain what have I got completely wrong?
http://jsfiddle.net/tPQ4s/
function runNums() {
this.topVar = 'blah';
return function(){
(function() {
(function() {
console.log(topVar);
})();
})();
}
}
var someFunc = runNums();
someFunc();
Without going too deep into the details, a closure technically describes a array like variable within the such called Activation Object that is handled from the javascript engine. An ActivationObject contains Variables declared by var, function declarations and formal parameters.
That means, anytime a new function (-context) is invoked, internally a new Activation Object is created. That object is part of the new Execution Context, a typicall EC looks like:
this context variable
Activation Object
[[Scope]]
The interesting part here is [[Scope]]. That variable contains all Activation Objects of all parent context and is filled when the EC is called. So now, when a function wants to access a variable, the name resolution process first looks into its own Activation Object, if nothing is found the search continues in the "Scope chain", which is just an Indexed search through our [[Scope]] variable (which again, is an array of parent contexts). Thats why we also speak a lot about "lexical scope" in ECMA-/Javascript.
Note: The above behavior is not described entirely, that would need several pages of text. Also it describes the ECMAscript3 262 specification. Things work a little different in ES5, but its still around the same thing
That is because the chain runs further up to the top context.
In the example, that would be:
window < runNums < anonymous < anonymous < anonymous
Variables living in any of these will be available in the last anonymous function. In runNums, only variables living in runNums or window will be available. In the first anonymous function, only its variables and those living in runNums or window will be available, etc.
this is nothing but the Window object here.
Here runNums is a global function and runNums() is equal to window.runNums(). So this is window and this.topVar is window.topVar. Obviously it will be accessible from anywhere.
Try this and see the difference
var someFunc = new runNums();
someFunc();
The deep nested functions have not been executed. You did not return them for executing.
I always thought that function a(){} is identical to a = function(){};
However, these two snippets behave differently:
a();
function a() {
alert("Booya");
}
Prints Booya.
a();
a = function() {
alert("Booya");
}
Fails with an exception, which makes sense, since a is really not defined when called.
So - what kind of 'magic' lets the first snippet work, even though a() is defined below its point of usage?
This is the difference between function declaration and function expression. This difference described well for example here.
In JavaScript all the declarations are hoisted. Means the variable can be used before it has been declared and function can be used before its declared.
It’s JavaScript’s default behaviour to move all the declarations at top of the current script.
But this feature may lead to bugs in application so we use strict mode directive to avoid bugs. Strict mode does not allow to use variables without declaration.
more info at here
See this article for an explanation: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
Function declarations and variable declarations are always moved ("hoisted") invisibly to the top of their containing scope by the JavaScript interpreter.
No magic, proper coding is required. AFAIK
document is loaded and parsed, functions are 'loaded'. The the script is being executed. So far no problem _a() _ is found.
no function is 'maped'. The script si executed line by line. It tries to call a() and THEN assign function to a global variable a
Functions are defined global. But if you assign a function to a variable, as you do in the second case, the scope rules for variables come into effect: You can not call the function before its variable was defined.