How to Achieve Dynamic Scoping in JavaScript Without Resorting to Eval

Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?

Attribute lookup falls through the prototype chain, which matches quite well to dynamic scopes. Just pass your own environment of dynamically-scoped variables to use around instead of using Javascript's lexical scoping.


// Polyfill for older browsers.  Newer ones already have Object.create.
if (!Object.create) {
// You don't need to understand this, but
Object.create = function(proto) {
// this constructor does nothing,
function cons() {}
// and we assign it a prototype,
cons.prototype = proto;
// so that the new object has the given proto without any side-effects.
return new cons();
};
}

// Define a new class
function dyn() {}
// with a method which returns a copy-on-write clone of the object.
dyn.prototype.cow = function() {
// An empty object is created with this object as its prototype. Javascript
// will follow the prototype chain to read an attribute, but set new values
// on the new object.
return Object.create(this);
}

// Given an environment, read x then write to it.
function g(env) {
console.log(env.x);
env.x = 2;
}
// Given an environment, write x then call f with a clone.
function f(env) {
env.x = 3;
g(env.cow());
}

// Create a new environment.
var env = new dyn();
// env -> {__proto__: dyn.prototype}
// Set a value in it.
env.x = 1;
// env -> {x: 1} // Still has dyn.prototype, but it's long so I'll leave it out.

f(env.cow());
// f():
// env -> {__proto__: {x: 1}} // Called with env = caller's env.cow()
// > env.x = 3
// env -> {x: 3, __proto__: {x: 1}} // New value is set in current object
// g():
// env -> {__proto__: {x: 3, __proto__: {x: 1}}} // caller's env.cow()
// env.x -> 3 // attribute lookup follows chain of prototypes
// > env.x = 2
// env -> {x: 2, __proto__: {x: 3, __proto__: {x: 1}}}

console.log(env.x);
// env -> {x: 1} // still unchanged!
// env.x -> 1

If JavaScript is dynamic scoping, what would be the last console.log() result in the following code?

See the example snippet with it's comments:

var a = 0;
var z = 1;
var x = 2;
var y = 4;
function f(n) {
a = n;
}
function g(){
console.log(`value of var a is ${a}`); // output var a value to console
}
function h(){
f(x); // a becomes 2 here since x = 2
g(); // output var a value to console
}
function k() {
var a = 0; // this sets a to 0 only in function scope
console.log(`function scope value of var a is ${a}`);
g(); // output var a value to console which is 1 here not 0
f(y); // a becomes 4 here since y = 4
}
f(z);
g();
k();
g();
h();
g();
console.log(`final value of var a is ${a}`);

Adopting dynamic scoping of variables

Sounds like you want to have your cake and eat it too, here. Some variables declared in inner scope should "hide" identical vars in outer scope, while others should not.

Sounds pretty easy to me; if a variable is declared in inner scope with identical signature (name and type) as one in an outer scope, the compiler should allow this "syntactic sugar" and simply create a new variable that is actually referred to by some mashup in whatever intermediate code is used (MSIL, JIL, assembly). Then, remove the var declaration from count, and most standards about intra-method scope will make this work exactly the way you want. You may optionally require use of the "new" keyword on the inner variable declaration to confirm to the compiler that, yes, you really do want a variable with the same name that "hides" the outer scope definition. So, your snippet would only change as follows:

var x = "foo";
var count = 0;

loop (/* condition */) {

var x = "bar"; //"hides" the outer x; maybe require "new" to confirm

print (x); // "bar"

count = count + 1; //works with the outer definition of count
}

print (x); // "foo"
print (count); // > 0

Javascript call with dynamic closure

Javascript uses lexical scope (based on where the code is declared), not dynamic scope.

If you are determined to try to do something that the language doesn't really encourage, you can force a string of code to be evaluated in your current execution context using eval(string of code here). In fact, you can do all sorts of odd things with eval(), but I'd much rather write code in a way that leverages the strengths of Javascript than to use a coding style that goes against the main design theme of the language (that's my opinion).

It's not entirely clear to me what problem you're trying to solve, but you can just pass a function as an argument and then call it via the argument from the called function.

// declare your function that takes a function reference an argument
function myFunction(callback) {
// call the function that was passed
callback();
}

function myDynamicFunc(){

// declare a local function
function myAlert() {
alert('Hello World');
}

// call your other function and pass it any function reference
myFunction(myAlert);
}

This will not pass an entire execution context. To do that, you'd have to package up the context in an object and pass a reference to the object, then dereference the properties from the object. That is typically how you pass an environment in JS.


You can use locally declared functions to provide access to parent scope from a callback (again lexical scope):

// declare your function that takes a function reference an argument
function doSomething(callback) {
// call the function that was passed
callback();
}

function myFunc() {
var myLocal1 = "Hello";
var myLocal2 = "World";

function callback() {
// when this is called, it has access to the variables of the parent scope
alert(myLocal1 + " " + myLocal2);
}

doSomething(myFunc);
}

You can even use it as a lasting closure:

// declare your function that takes a function reference an argument
function doSomething(callback) {
// call the function that was passed
callback();
}

function myFunc() {
var myLocal1 = "Hello";
var myLocal2 = "World";

function callback() {
// when this is called, it has access to the variables of the parent scope
// which are still alive in this closure even though myFunc has finished
// executing 10 minutes ago
alert(myLocal1 + " " + myLocal2);
}

// call the callback function 10 minutes from now,
// long after myFunc has finished executing
setTimeout(callback, 10 * 60 * 1000);
}

Here are some reference articles on lexical and dynamic scope in Javascript:

Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?

Are variables statically or dynamically "scoped" in javascript?

What is lexical scope?

Is there a way to dynamically modify a closure of a function in JavaScript?

Your problem can be decomposed into two parts:

  1. Dynamic scoping - http://en.wikipedia.org/wiki/Scope_(computer_science)#Dynamic_scoping
  2. Variable preservation across calls

The first part can be easily tackled using eval. Read the following StackOverflow question for more details: Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?

The second part requires that you store the intermediate value of the variable x somewhere and restore it after every function call. The best place to store it in this case would be on the function b itself.

This is what your code would look like:

function a() {
return ++x; // I believe you want prefix increment, not postfix
}

function b() {
var x = b.x;
eval(String(a)); // dynamic scoping
b.x = a();
return x;
}

b.x = 0;

console.log(b(), b(), b());

You can see the demo here: http://jsfiddle.net/ucGxD/1/

Lexical scoping vs dynamic scoping

As we know, C doesn't have dynamic scoping, but assuming it did, the program would print 3 4.

In main, a and b are the global ones. a will be set to 2, as we will see that this is what p will return.

In p, called from main, b is still the global one, but a is the one local in p. The local a is set to 0, but will soon disappear. The global b is set to 1. The local p is set to 2, and 2 will be returned. Now the global b is 1.

In q, called from main, a is the global one, but b is the one local in q. Here the global a is set to 3, and the local b is set to 4.

In print, called from q, a is the global one (which has the value 3), and b is the one local in q (which has the value 4).

It is in this last step, inside the function print, that we see a difference from static scoping. With static scoping a and b would be the global ones. With dynamic scoping, we have to look at the chain of calling functions, and in q we find a variable b, which will be the b used inside print.

How to write function-y accepting parameter-fct_x which accesses var-a which is required to be defined in function-y?

Following answer is inspected by Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?

function x() {
return a + 1; // it can be anything accessing var-a.
}

function y(fct_x) {
var a = 2;
var x = eval("(" + String(fct_x) + ")"); // eval(String(fct_x)) will return undefined.
// eval("(" + String(fct_x) + ")") will return a function
console.log(x()); // 3
}

y(x); // exception: see above
// x is any function which will access var-a which is required to be defined in function-y


Related Topics



Leave a reply



Submit