Does Eval really introduce dynamic scoping to JavaScript? - javascript

People say that Eval brings dynamic scope into JavaScript, but I don't see how that statement is valid. Using Eval evaluates the expression using the same lexical environment/variable environment as the calling environment (reference ECMA 262 v. 5). The Assignment or declaration of the expression is obviously dynamic, but I don't think it is valid to say that it introduces dynamic scope.
Am I right in saying that Eval doesn't introduce dynamic scope?

Yes and no.
In a strict sense, no; the language still operates lexically (except with respect to this, which is always dynamically scoped).
However, if you read the whole question you linked to, you'll see that the asker is using eval to emulate dynamic scope.
var x = 1;
function g() {
print(x);
x = 2;
}
function f() {
// create a new local copy of `g` bound to the current scope
// explicitly assign it to a variable since functions can be unnamed
// place this code in the beginning of the function - manual hoisting
var g = eval(String(g));
var x = 3;
g();
}
f(); // prints 3
print(x); // prints 1
Emulating dynamic scope is totally achievable the way that the asker of that question is using it. The asker is using eval to actually import an externally defined function into the scope of another function. This requires stringifying the function and redeclaring it. So the externally defined function isn't really being run within the scope of another function (this example doesn't really demonstrate dynamic scope in a strict sense) because a whole new function is declared. That being said, the asker's intention is to emulate dynamic scope, and he is achieving that with eval.

Related

Is there block scope really in JavaScript (as a first-class language concept)?

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...)

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.

eloquent javascript chapter regarding modules. On scopes and eval function

Eloquent javscript writes this in chapter 10 of the modules chapter:
The most obvious way is the special operator eval, which will execute
a string of code in the current scope. This is usually a bad idea
because it breaks some of the sane properties that scopes normally
have, such as being isolated from the outside world.
Here is the code:
function evalAndReturnX(code) {
eval(code);
return x;
}
console.log(evalAndReturnX("var x = 2"));
console.log(x)
console.log(code)
it outputs:
2
ReferenceError: x is not defined (line 7)
which seems normal? What gives? I don't see any violation of scope?
Eval has some tricky semantics. From mdn:
If you use the eval function indirectly, by invoking it via a
reference other than eval, as of ECMAScript 5 it works at global scope
rather than local scope; this means, for instance, that function
declarations create global functions, and that the code being
evaluated doesn't have access to local variables within the scope
where it's being called.
So in your case, because you're calling eval directly within that function, it defines x within the lexical scope of that function, not available to the global scope. However, if you were to do something like this:
var _eval = eval;
function e() {
_eval("var x = 2");
return x;
}
console.log(e());
console.log(x);
It would work in both cases, since this would define x in the global scope, which would be inherited by the lexical scope of the callee.
See this fiddle for a working example

Why does this work in javascript?

Just now,I saw some code like this:
if(condition){
var xx='sss';
}
//do something
if(condition){
console.info(xx);
}
Now, I just wonder why the second if statement work? How can it access the xx variable since it is a local variable defined in another if statement?
var in JavaScript is scoped to the containing execution context (e.g., the whole function's scope, or the whole global scope if the var is at global scope), not the block. JavaScript doesn't (yet) have block scope (ECMAScript6 looks likely to add it, via the new let keyword).
The code you've quoted is exactly equivalent to this:
var xx;
if(condition){
xx='sss';
}
//do something
if(condition){
console.info(xx);
}
This is covered by Section 10.5 of the specification, which describes what the engine does when entering a new execution context. (It's basically a two-phase process, first setting up all the declarations, and then executing step-by-step code.)
More: Poor misunderstood var
In JavaScript the scope is exacted to the closure (the last enclosing function block, or defaults to the window object). When a variable is declared anywhere within that function block it is hoisted to the top of the scope, so in essence a variable exists as undefined starting at the very top of the scope if it is declared anywhere in the scope.
Think of it like this, when the code begins executing it scans all the instructions for declarations and allocates the symbol name starting immediately.
console.log(x); // undefined
console.log(y); // error: Uncaught ReferenceError: y is not defined
var x;
for that matter you can take it to extremes:
console.log(x); // undefined, not an error
while (false) {
if (false) {
var x;
}
}
even though var x can't possibly be reached, and during execution would be optimized away completely. the engine will still hoist the variable to the top of the scope
hope this helps -ck
useful link: http://www.youtube.com/watch?v=taaEzHI9xyY&feature=youtu.be#t=42m57s
var declarations affect the entire scope of the smallest containing function or program. JavaScript is not block scoped.
Crock says:
Variable Declarations
All variables should be declared before used. JavaScript does not require this, but doing so makes the program easier to read and makes it easier to detect undeclared variables that may become implied globals. Implied global variables should never be used.
The var statements should be the first statements in the function body.
It is preferred that each variable be given its own line and comment. They should be listed in alphabetical order.
var currentEntry; // currently selected table entry
var level; // indentation level
var size; // size of table
JavaScript does not have block scope, so defining variables in blocks can confuse programmers who are experienced with other C family languages. Define all variables at the top of the function.
Use of global variables should be minimized. Implied global variables should never be used.
Note, this is changing with the let statement, and in current JavaScript (EcmaScript 5), the variable name in a catch block is block scoped.
javascript doesn't have block scope, so var xx='sss' is either locally scoped (if your sample code is inside a function) or globally scoped (if your sample code is not contained in a function).
JavaScript is a dynamic language, that isn't always picky about things like variable scoping. So, this "feature" allows you to write the code
if (condition) {
var xx = 'sss';
} else {
var xx = 'ttt';
}
// do something
if (condition) {
console.info(xx);
}
I would recommend avoiding this, since it makes your program harder to understanda and reason about.
If you declare a variable using var within a function, the variable is scoped to within that function. An if statement is not a function.
I'm assuming in this case both if statements are within the same function and therefore xx is in scope?
If a variable is declared inside a conditional statement, it is still available anywhere following the declaration in the containing function (or globally if the conditional is not in a function). However, it will equal undefined if the condition evaluates to false, unless the variable is later assigned a value.
If a local variable is referenced globally or in another function, a JavaScript error will occur. Depending on your browser, the error may say the variable "is not defined" or "is undefined". This is different from the variable equaling undefined like mentioned above, because a variable that equals undefined can still be referenced.

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