How to programmatically inspect the JavaScript scope chain? - javascript

In a JavaScript debugger, I can manually inspect the scope chain of a function. For instance, when executing foo() on this piece of code:
var x1 = "global";
var foo = (function main () {
var x2 = "inside obj";
return function internalFoo () {
var x3 = "inside internalFoo";
console.log (x1+','+x2+','+x3); // get the scopes
};
})();
foo ();
and setting a breakpoint on the console.log, I see the following scopes:
Is there some means to do this programmatically?
How can I inspect what is defined at every scope level?

I am (pretty) sure this is not possible.Not even the Chrome-debugger keeps track of your scope all the time, but only when it hits a breakpoint. Keeping track of the scope chain for all the time would cost way too much memory (depending on the complexity of your closures and contexts). See this feature request for further information: https://groups.google.com/forum/#!topic/google-chrome-developer-tools/wKEMpKjXR7s
ECMA 262 (10.3.1) describes how Identifier Resolution has to be done, the most important part of this is to call GetIdentifierReference (lex, name, strict) which is described in ECMA 262 (10.2.1). As far as I know there is no command in any implementation of ECMAScript to call this function at runtime.
However this question (or to be precise it's answer) might be interesting as it comes at least closer to what you asked for.

Related

How to carry forward arguments into child function? [duplicate]

With this code:
function baz() {
var x = "foo";
function bar() {
debugger;
};
bar();
}
baz();
I get this unexpected result:
When I change the code:
function baz() {
var x = "foo";
function bar() {
x;
debugger;
};
bar();
}
I get the expected result:
Also, if there is any call to eval within the inner function, I can access my variable as I want to do (doesn't matter what I pass to eval).
Meanwhile, Firefox dev tools give the expected behavior in both circumstances.
What's up with Chrome that the debugger behaves less conveniently than Firefox? I have observed this behavior for some time, up to and including Version 41.0.2272.43 beta (64-bit).
Is it that Chrome's javascript engine "flattens" the functions when it can?
Interestingly if I add a second variable that is referenced in the inner function, the x variable is still undefined.
I understand that there are often quirks with scope and variable definition when using an interactive debugger, but it seems to me that based on the language specification there ought to be a "best" solution to these quirks. So I am very curious if this is due to Chrome optimizing further than Firefox. And also whether or not these optimizations can easily be disabled during development (maybe they ought to be disabled when dev tools are open?).
Also, I can reproduce this with breakpoints as well as the debugger statement.
I've found a v8 issue report which is precisely about what you're asking.
Now, To summarize what is said in that issue report... v8 can store the variables that are local to a function on the stack or in a "context" object which lives on the heap. It will allocate local variables on the stack so long as the function does not contain any inner function that refers to them. It is an optimization. If any inner function refers to a local variable, this variable will be put in a context object (i.e. on the heap instead of on the stack). The case of eval is special: if it is called at all by an inner function, all local variables are put in the context object.
The reason for the context object is that in general you could return an inner function from the outer one and then the stack that existed while the outer function ran won't be available anymore. So anything the inner function accesses has to survive the outer function and live on the heap rather than on the stack.
The debugger cannot inspect those variables that are on the stack. Regarding the problem encountered in debugging, one Project Member says:
The only solution I could think of is that whenever devtools is on, we would deopt all code and recompile with forced context allocation. That would dramatically regress performance with devtools enabled though.
Here's an example of the "if any inner function refers to the variable, put it in a context object". If you run this you'll be able to access x at the debugger statement even though x is only used in the foo function, which is never called!
function baz() {
var x = "x value";
var z = "z value";
function foo () {
console.log(x);
}
function bar() {
debugger;
};
bar();
}
baz();
Like #Louis said it caused by v8 optimizations.
You can traverse Call stack to frame where this variable is visible:
Or replace debugger with
eval('debugger');
eval will deopt current chunk
I've also noticed this in nodejs. I believe (and I admit this is only a guess) that when the code is compiled, if x does not appear inside bar, it doesn't make x available inside the scope of bar. This probably makes it slightly more efficient; the problem is someone forgot (or didn't care) that even if there's no x in bar, you might decide to run the debugger and hence still need to access x from inside bar.
Wow, really interesting!
As others have mentioned, this seems to be related to scope, but more specifically, related to debugger scope. When injected script is evaluated in the developer tools, it seems to determine a ScopeChain, which results in some quirkiness (since it's bound to the inspector/debugger scope). A variation of what you posted is this:
(EDIT - actually, you mention this in your original question, yikes, my bad!)
function foo() {
var x = "bat";
var y = "man";
function bar() {
console.log(x); // logs "bat"
debugger; // Attempting to access "y" throws the following
// Uncaught ReferenceError: y is not defined
// However, x is available in the scopeChain. Weird!
}
bar();
}
foo();
For the ambitious and/or curious, scope (heh) out the source to see what's going on:
https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/inspector
https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/debugger
I suspect this has to do with variable and function hoisting. JavaScript brings all variable and function declarations to the top of the function they are defined in. More info here: http://jamesallardice.com/explaining-function-and-variable-hoisting-in-javascript/
I bet that Chrome is calling the break point with the variable unavailable to the scope because there is nothing else in the function. This seems to work:
function baz() {
var x = "foo";
function bar() {
console.log(x);
debugger;
};
bar();
}
As does this:
function baz() {
var x = "foo";
function bar() {
debugger;
console.log(x);
};
bar();
}
Hope this, and / or the link above helps. These are my favorite kind of SO questions, BTW :)
I seem to have access to _this. Where this is undefined in chrome inspector for me, _this seems to reference the appropriate context (and is probably what's used to as > local > this in the stack trace inspector?).
I know this is a bit old, but my issue was minification using babel - i.e. --presets minify
When my js code was built and minified my local variables were undefined; when not minified I was able to see values of variables in the console.

Why is execution context needed for JS

I am new to JS and was learning the role of execution context in JS and asked myself what is the benefit of execution context in JS and why JS is run via execution context. The second question is as we know there are global and functional execution contexts and each context has two phases creation phase and execution phase. So, why we need these two phases? what is the point of having them.
The concept of an "execution context" provides a way of reasoning about what happens when the global environment is created and executed, or when a function is called. It's a conceptual container for the local variables (globals, in the case of the global environment), parameters (for functions), etc. A JavaScript engine can be written without literally having any object it calls an "execution context," as long as it implements the language in keeping with the spec's defined execution context behavior.
One thing that the execution context helps explain is the behavior of closures. A function created within a given execution context has (conceptually) a reference to that context, even after the function call related to the context has completed:
function foo(answer) {
return function say() {
console.log(answer);
};
}
const s = foo(42);
s(); // 42
That works because the function say has a reference to the context of the call to foo that created it (well, more specifically to the thing called its "lexical environment"). That lexical environment continues to exist after foo returns because something still has a reference to it (say). So the call to say afterward works.
The reason for having two phases is to allow use of identifiers before their declaration. This is primarily useful for function declarations:
main();
function main() {
console.log("Worked");
}
The first phase processes the function declarations (and var statements), and then the step-by-step phase runs the code. Without the first phase, the code above would fail as of main(); because main would be undeclared. Of course, with the simple example above, you could just move the main(); call to after the function declaration, but more complicated cases become harder to solve in that way. Languages that didn't have two phases (early C, for instance) had to provide a mechanism for "forward declaring" things that would be defined later. Having two phases means JavaScript doesn't have to have those. (To be fair, C also differs from JavaScript in that it needs to know what all identifiers refer to during compilation, even if the identifiers are in code within functions. So it needed forward declarations just to allow foo and bar to call one another. JavaScript doesn't check the identifiers used within functions until the function is called, so some of the reasons for forward declarations in C wouldn't come up in JavaScript even if it didn't have two phases.)
It wasn't perfectly successful. Having var statements initialize the variables they declare with undefined before the var statement is reached in the code was often the source of bugs and confusion:
console.log(answer); // undefined
var answer = 42;
It's easy for people to be confused by the fact that half of the var answer = 42; was done early (the var answer part), but the other half (answer = 42;) isn't done until later when that statement is reached.
That's why let and const create, but don't initialize, their variables during that first phase. You can use a variable above where it's declared, but only in code that runs after the initialization:
function foo() {
console.log(answer);
}
// foo(); <== Would fail, `answer` isn't initialized yet
let answer = 42;
foo(); // Works, logs 42

Chrome console can not access unused variable in lexical scope? [duplicate]

With this code:
function baz() {
var x = "foo";
function bar() {
debugger;
};
bar();
}
baz();
I get this unexpected result:
When I change the code:
function baz() {
var x = "foo";
function bar() {
x;
debugger;
};
bar();
}
I get the expected result:
Also, if there is any call to eval within the inner function, I can access my variable as I want to do (doesn't matter what I pass to eval).
Meanwhile, Firefox dev tools give the expected behavior in both circumstances.
What's up with Chrome that the debugger behaves less conveniently than Firefox? I have observed this behavior for some time, up to and including Version 41.0.2272.43 beta (64-bit).
Is it that Chrome's javascript engine "flattens" the functions when it can?
Interestingly if I add a second variable that is referenced in the inner function, the x variable is still undefined.
I understand that there are often quirks with scope and variable definition when using an interactive debugger, but it seems to me that based on the language specification there ought to be a "best" solution to these quirks. So I am very curious if this is due to Chrome optimizing further than Firefox. And also whether or not these optimizations can easily be disabled during development (maybe they ought to be disabled when dev tools are open?).
Also, I can reproduce this with breakpoints as well as the debugger statement.
I've found a v8 issue report which is precisely about what you're asking.
Now, To summarize what is said in that issue report... v8 can store the variables that are local to a function on the stack or in a "context" object which lives on the heap. It will allocate local variables on the stack so long as the function does not contain any inner function that refers to them. It is an optimization. If any inner function refers to a local variable, this variable will be put in a context object (i.e. on the heap instead of on the stack). The case of eval is special: if it is called at all by an inner function, all local variables are put in the context object.
The reason for the context object is that in general you could return an inner function from the outer one and then the stack that existed while the outer function ran won't be available anymore. So anything the inner function accesses has to survive the outer function and live on the heap rather than on the stack.
The debugger cannot inspect those variables that are on the stack. Regarding the problem encountered in debugging, one Project Member says:
The only solution I could think of is that whenever devtools is on, we would deopt all code and recompile with forced context allocation. That would dramatically regress performance with devtools enabled though.
Here's an example of the "if any inner function refers to the variable, put it in a context object". If you run this you'll be able to access x at the debugger statement even though x is only used in the foo function, which is never called!
function baz() {
var x = "x value";
var z = "z value";
function foo () {
console.log(x);
}
function bar() {
debugger;
};
bar();
}
baz();
Like #Louis said it caused by v8 optimizations.
You can traverse Call stack to frame where this variable is visible:
Or replace debugger with
eval('debugger');
eval will deopt current chunk
I've also noticed this in nodejs. I believe (and I admit this is only a guess) that when the code is compiled, if x does not appear inside bar, it doesn't make x available inside the scope of bar. This probably makes it slightly more efficient; the problem is someone forgot (or didn't care) that even if there's no x in bar, you might decide to run the debugger and hence still need to access x from inside bar.
Wow, really interesting!
As others have mentioned, this seems to be related to scope, but more specifically, related to debugger scope. When injected script is evaluated in the developer tools, it seems to determine a ScopeChain, which results in some quirkiness (since it's bound to the inspector/debugger scope). A variation of what you posted is this:
(EDIT - actually, you mention this in your original question, yikes, my bad!)
function foo() {
var x = "bat";
var y = "man";
function bar() {
console.log(x); // logs "bat"
debugger; // Attempting to access "y" throws the following
// Uncaught ReferenceError: y is not defined
// However, x is available in the scopeChain. Weird!
}
bar();
}
foo();
For the ambitious and/or curious, scope (heh) out the source to see what's going on:
https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/inspector
https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/debugger
I suspect this has to do with variable and function hoisting. JavaScript brings all variable and function declarations to the top of the function they are defined in. More info here: http://jamesallardice.com/explaining-function-and-variable-hoisting-in-javascript/
I bet that Chrome is calling the break point with the variable unavailable to the scope because there is nothing else in the function. This seems to work:
function baz() {
var x = "foo";
function bar() {
console.log(x);
debugger;
};
bar();
}
As does this:
function baz() {
var x = "foo";
function bar() {
debugger;
console.log(x);
};
bar();
}
Hope this, and / or the link above helps. These are my favorite kind of SO questions, BTW :)
I seem to have access to _this. Where this is undefined in chrome inspector for me, _this seems to reference the appropriate context (and is probably what's used to as > local > this in the stack trace inspector?).
I know this is a bit old, but my issue was minification using babel - i.e. --presets minify
When my js code was built and minified my local variables were undefined; when not minified I was able to see values of variables in the console.

Learning JavaScript: Lexical Versus Dynamic Scoping

So I was reading this book, following along with the code examples and running them using node console. In Chapter 7, paragraph 'Lexical Versus Dynamic Scoping', the author claims that the following code will result in an error:
const x = 3;
function f() {
console.log(x); // this will work
console.log(y); // this will cause a crash
}
const y = 3;
f();
This is due to the fact that (as the book reads)
Scoping in JavaScript is lexical...
and
Lexical scoping means whatever variables are in scope where you define a function from (as opposed to when you call it) are in scope in the function.
However this code runs just fine, and produces the following output:
3
3
I have searched for other examples of lexical scoping and what it means, but they all seem to suggest slightly different things from what the book says. So I am left wondering, is the explanation in the book completely wrong or am I missing something very basic?
The quoted description…
Lexical scoping means whatever variables are in scope where you define a function from (as opposed to when you call it) are in scope in the function.
… is correct.
The code example is wrong. The function f has access to any variable (or constant) that exists in the scope that it is declared in. What the book appears to get wrong is that constants can be added to that scope after the function has been declared.
Where the function is declared matters. When it is declared, not so much.
The above code will work fine. However, this will fail.
const x = 3;
function f() {
console.log(x); // this will work
console.log(y); // this will cause a crash
}
f();
const y = 3;
That is because y is not yet declared or defined at the time of function invocation and
x is accessible because Scoping is lexical and function will access the x defined in global scope, if not found on local.
This can be understood by this example more clearly
function b(){
console.log(v) //=> 1
} //lexically defined at global scope
function a(){
var v = 2
console.log(v) //=> 2
b() //called in the scope of a()
}
var v = 1
a()
console.log(v) //=> 1
console.log in b() will give 1 because according to lexical global scope v = 1. But according to Dynamic Scope (created by a()) it should be 2, which is not the case.
Hope this helps :)
This book looks quite old - 11 years ago. The world is no longer the same. Now we see that JavaScript changes day after day. I think that we should not use any book produced since 2 years ago.
The problem you (and the book) mentioned is relating to another concept: strict mode. In ECMAScript 5, you can turn on this mode by adding "use strict" on top of your JavaScript file. So that, you would see some errors throw while they don't in regular mode. If you want to get the example works, you may need to find an old browser, IE8 or such - I'm not sure, then create a HTML file, then add your script to, then turn on strict mode, it may give you the same result as the author said.
Strict mode is no longer the case in JavaScript today - I would like to talk about ECMAScript 6, or ES6, or ECMAScript 2015. We simple don't need to care about strict mode while writing JavaScript now. I have many module on npmjs.org but none of them have "use strict" declaration at all.
Just my two cents: in programming, don't read old books, because everything changes so fast.

What is the scope of a function in Javascript/ECMAScript?

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.'
}

Categories