I'm using dynamic scoping to simulate pointers in JavaScript as follows:
var ptr = (function () {
var ptr = "(" + String(function (value) {
if (value === void 0) return upvalue;
else upvalue = value;
}) + ")";
return function (upvalue) {
return ptr.replace(/upvalue/g, upvalue);
};
}());
function swap(xptr, yptr) {
var t = xptr();
xptr(yptr());
yptr(t);
}
var x = 2;
var y = 3;
alert([x, y]);
swap(eval(ptr("x")), eval(ptr("y")));
alert([x, y]);
Is there any other way to achieve the same results (i.e. without resorting to eval)? It just seems like too much boilerplate.
Since the only thing you're using the pointer for is to dereference it to access another variable, you can just encapsulate it in a property.
function createPointer(read, write) {
return { get value() { return read(); }, set value(v) { return write(v); } };
}
To create a pointer, pass the accessor methods which read and write the variable being pointed to.
var i;
var p = createPointer(function() { return i; }, function(v) { i = v; });
// p is now a "pointer" to i
To dereference a pointer, access its value. In other words, where in C you would write *p here you write p.value.
i = "initial";
alert(p.value); // alerts "initial"
p.value = "update";
alert(i); // alerts "update"
p.value += "2";
alert(i); // alerts "update2"
You can create multiple pointers to the same variable.
var q = createPointer(function() { return i; }, function(v) { i = v; });
// q is also a "pointer" to i
alert(q.value); // alerts "update2"
q.value = "written from q";
alert(p.value); // alerts "written from q"
You can change what a pointer points to by simply overwriting the pointer variable with another pointer.
var j = "other";
q = createPointer(function() { return j; }, function(v) { j = v; });
// q is now a "pointer" to j
You can swap two variables through pointers.
function swap(x, y) {
var t = x.value;
x.value = y.value;
y.value = t;
}
Let's swap the values of i and j by using their pointers.
swap(p, q);
alert(i); // alerts "other"
alert(j); // alerts "written from q"
You can create pointers to local variables.
function example() {
var myVar = "myVar as local variable from example";
var r = createPointer(function() { return myVar; }, function(v) { myVar = v; });
swap(p,r);
alert(i); // alerts "myVar as local variable from example"
alert(myVar); // alerts "other"
}
example();
Through the magic of closures, this gives you a way to simulate malloc.
function malloc() {
var i;
return createPointer(function() { return i; }, function(v) { i = v; });
}
var p = malloc(); // p points to a variable we just allocated from the heap
p.value = 2; // write a 2 into it
Your magic trick works too:
var flowers = new Misdirection(
createPointer(function() { return flowers; }, function(v) { flowers = v; }));
flowers.abracadabra();
alert(flowers);
function Misdirection(flowers) {
this.abracadabra = function() {
flowers.value = new Rabbit;
};
}
function Rabbit() {
this.toString = function() { return "Eh... what's up doc?" };
}
Unfortunately, the only ways to reference a variable in Javascript are accessing it directly (something we don't want, since it does static binding) or passing its name in string form to eval.
If you really want to avoid eval, what you can do is try to have your variables inside objects that act as scopes, since this would let you use [] subscript notation to access a variable given its name. Note that if all pointers you create are to global variables then this is already the case, since global variables are also made to be properties of the global window object.
function pointer(scope, varname){
return function(x){
if(arguments.length <= 0){ //The explicit arguments.length lets us set the pointed variable to undefined too.
return scope[varname];
}else{
return (scope[varname] = x);
}
}
};
var vars = {
x: 1
};
var y = 2; // "normal" variables will only work if they are global.
swap( pointer(vars, 'x'), pointer(window, 'y') );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With