Is it possible to achieve dynamic scoping in JavaScript without resorting to eval? -
javascript has lexical scoping means non-local variables accessed within function resolved variables present in parents' scope of function when defined. in contrast dynamic scoping in non-local variables accessed within function resolved variables present in calling scope of function when called.
x=1 function g () { echo $x ; x=2 ; } function f () { local x=3 ; g ; } f # print 1, or 3? echo $x # print 1, or 2?
the above program prints 1 , 2 in lexically scoped language, , prints 3 , 1 in dynamically scoped language. since javascript lexically scoped print 1 , 2 demonstrated below:
var print = x => console.log(x); var x = 1; function g() { print(x); x = 2; } function f() { var x = 3; g(); } f(); // prints 1 print(x); // prints 2
although javascript doesn't support dynamic scoping can implement using eval
follows:
var print = x => console.log(x); var x = 1; function g() { print(x); x = 2; } function f() { // create new local copy of `g` bound current scope // explicitly assign variable since functions can unnamed // place code in beginning of function - manual hoisting var g_ = eval("(" + string(g) + ")"); var x = 3; g_(); } f(); // prints 3 print(x); // prints 1
i know if there exists possible way achieve same result without resorting eval
.
edit: i'm trying implement without using eval
:
var print = x => console.log(x); function class(clazz) { return function () { var constructor; var constructor = eval("(" + string(clazz) + ")"); constructor.apply(this, arguments); constructor.apply(this, arguments); }; } var rectangle = new class(function () { var width, height; constructor = function (w, h) { width = w; height = h; }; this.area = function () { return width * height; }; }); var rectangle = new rectangle(2, 3); print(rectangle.area());
i know it's not example general idea use dynamic scoping create closures. think pattern has lot of potential.
attribute lookup falls through prototype chain, matches quite dynamic scopes. pass own environment of dynamically-scoped variables use around instead of using javascript's lexical scoping.
// polyfill older browsers. newer ones have object.create. if (!object.create) { // don't need understand this, object.create = function(proto) { // constructor nothing, function cons() {} // , assign prototype, cons.prototype = proto; // new object has given proto without side-effects. return new cons(); }; }
// define new class function dyn() {} // method returns copy-on-write clone of object. dyn.prototype.cow = function() { // empty object created object prototype. javascript // follow prototype chain read attribute, set new values // on new object. return object.create(this); }
// given environment, read x write it. function g(env) { console.log(env.x); env.x = 2; } // given environment, write x call f clone. function f(env) { env.x = 3; g(env.cow()); }
// create new environment. var env = new dyn(); // env -> {__proto__: dyn.prototype} // set value in it. env.x = 1; // env -> {x: 1} // still has dyn.prototype, it's long i'll leave out. f(env.cow()); // f(): // env -> {__proto__: {x: 1}} // called env = caller's env.cow() // > env.x = 3 // env -> {x: 3, __proto__: {x: 1}} // new value 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
Comments
Post a Comment