JavaScript has lexical scoping which means that non-local variables accessed from within a function are resolved to variables present in the parents' scope of that function when it was defined. This is in contrast to dynamic scoping in which non-local variables accessed from within a function are resolved to variables present in the calling scope of that function when it is called.
x=1
function g () { echo $x ; x=2 ; }
function f () { local x=3 ; g ; }
f # does this print 1, or 3?
echo $x # does this print 1, or 2?
The above program prints 1 and then 2 in a lexically scoped language, and it prints 3 and then 1 in a dynamically scoped language. Since JavaScript is lexically scoped it will print 1 and then 2 as 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 we can implement it using eval
as follows:
var print = x => console.log(x);
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
I would like to know if there exists another possible way to achieve the same result without resorting to eval
.
Edit: This is what I'm trying to 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 that it's not a very good example but the general idea is to use dynamic scoping to create closures. I think this pattern has a lot of potential.
You can simulate dynamic scoping using global variables, if you have a way to do syntactic sugar (e.g. macros with gensyms) and if you have unwind-protect.
The macro can appear to rebind the dynamic variable by saving its value in a hidden lexical and then assigning a new value. The unwind-protect code ensures that no matter how that block terminates, the original value of the global will be restored.
Lisp pseudocode:
Of course, this is not a thread-safe way of doing dynamic scope, but if you aren't doing threading, it will do! We would hide it behind a macro like:
So if you have unwind-protect in Javascript, and a macro preprocessor to generate some syntactic sugar (so you're not manually open-coding all your saves and unwind-protected restores) it might be doable.
I know this doesn't exactly answer the question but it's too much code to put into a comment.
As an alternative approach, you may want to look into ExtJS's
extend
function. This is how it works:With public properties instead of private variables:
To add a note on this topic:
In JavaScript whenever you make use of:
function declaration statement or function definition expression then local variables will have Lexical Scoping.
Function constructor then local variables will refer to the global scope (top-level code)
this
is the only built-in object in JavaScript that has a dynamic scoping and is set through the execution (or invocation) context.So to answer to your question, In JS the
this
is already dynamically scoped feature of the language and you even don't need to emulate another one.I don't think so.
That is not how the language works. You have to use something other than variables to refer to this state information. The most "natural" way being to use properties of
this
, I guess.In your case, instead of trying to use dynamic scoping to set the constructor, what if you used the return value?
Why didn't anybody say
this
?You can pass variables from the calling scope into the called function by binding it a context.
Perhaps it's worth mentioning that in strict mode, all functions have no "environment" sent to them by default (
this
is null). In non strict mode the global object is the defaultthis
value for a called function.