admin管理员组文章数量:1320608
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.
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.
- 4 Why do you want to do this? Generally speaking, if you try to write JavaScript like it's a different language you're going to end up with some really ugly code. – James M Commented Apr 23, 2012 at 13:06
- 4 Ugh, that's wrong on so many levels... Is there any particular problem you want to solve or is this an academic question? – Tomalak Commented Apr 23, 2012 at 13:07
- 1 If you need pointers without eval use arrays. – Dewfy Commented Apr 23, 2012 at 13:08
- @JamesMcLaughlin - It doesn't matter if the code is ugly. It's just boilerplate for a language that I'm building on top of JavaScript (like CoffeeScript). The end user doesn't need to interact with the JavaScript boilerplate at all. Hence it's alright if it's not pretty. =) – Aadit M Shah Commented Apr 23, 2012 at 15:19
-
1
Maybe I just don't understand what problem you are trying to solve. I don't see any benefit in pointers within the context of JavaScript. But I do see you using
eval
and mutating stringified function bodies with regular expressions and that can't be right. For one: There are no "memory locations" in a memory-managed language. Further: Big and plex JS libraries have been written without the need to "simulate" pointers. It just does not make sense to me, and it probably won't until you can point out a reasonable use case. – Tomalak Commented Apr 24, 2012 at 7:29
5 Answers
Reset to default 5Since 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') );
something like that?
function swap(a,b,scope) {
var t = scope[a];
scope[a] = scope[b];
scope[b] = t;
}
x = 2;
y = 3;
alert([x,y]);
swap('x', 'y',this);
alert([x,y]);
Here is one way of doing it with an object:
var obj = {
x:2,
y:3
},
swap = function(p1, p2){
var t = obj[p1];
obj[p1] = obj[p2];
obj[p2] = t;
};
console.log( obj.x, obj.y );
swap('x', 'y');
console.log( obj.x, obj.y );
Edit:
@Tomalak - Consider the following JavaScript program:
var flowers = new Misdirection;
flowers.abracadabra();
alert(flowers);
function Misdirection() {
this.abracadabra = function () {
this = new Rabbit;
};
}
function Rabbit() {
this.toString = function () {
return "Eh... What's up, doc?";
};
}
The above program throws ReferenceError: Cannot assign to 'this'
. Pointers can be used to solve this problem; and although it won't update the this
pointer, it will do the next best thing - update the only reference to the this
pointer.
We could make the above program work without using pointers by replacing this
with flowers
. However by doing so the misdirection magic trick will only work for one instance of the constructor. Pointers allow us to make it work for any number of instances.
It's not possible to achieve the same results by using Function.call
, Function.apply
, or Array.map
. In addition if the constructor returns an explicit value then it's useless to override the this
pointer anyway. The program I wrote below (using pointers) will work even if I returned the abracadabra
function from Misdirection
and called flowers()
instead of flowers.abracadabra()
.
Original:
Simulating pointers in JavaScript is a really powerful hack. For example it can be used to perform a magic trick as follows:
var flowers = new Misdirection(&flowers);
flowers.abracadabra();
alert(flowers);
function Misdirection(flowers) {
this.abracadabra = function () {
*flowers = new Rabbit;
};
}
function Rabbit() {
this.toString = function () {
return "Eh... What's up, doc?";
};
}
That's all nice and dandy, but the real power of simulating pointers in JavaScript shines through when we push the envelope:
var Square = new Class(function (ctor, uber) {
*ctor = constructor;
var side;
function constructor(length) {
side = length;
}
this.area = function () {
return side * side;
};
return &uber;
});
var Cube = new Class(function (ctor, uber) {
*ctor = constructor;
function constructor(side) {
uber(side);
}
this.area = function () {
return 6 * uber.area();
};
return &uber;
}, Square);
var cube = new Cube(5);
alert(cube.area());
function Class(claus, Uber) {
Claus.__proto__ = Uber === void 0 ? Class.prototype : Uber;
return Claus;
function Claus() {
var self = this;
var called;
var uber = Uber === void 0 ? function () {
throw new Error("No uber class specified.");
} : function () {
if (!called) {
called = "Cannot call uber class constructor more than once.";
var args = Array.prototype.slice.call(arguments);
args = Array.prototype.concat.call([null], args);
var base = new (Function.prototype.bind.apply(Uber, args));
self.__proto__.__proto__ = base;
self.__proto__.__proto__.constructor = Claus;
*uber = base;
} else throw new Error(called);
};
var constructor = new Function;
uber = claus.call(this, &constructor, uber);
constructor.apply(this, arguments);
};
}
Obviously this is too much boilerplate, but it does demonstrate just how powerful closures are. What's truly amazing is that we can use this boilerplate to simulate classical object oriented programming in JavaScript. For example the following code can be transpiled to the above program (although we'll need to write a full fledged parser to do so):
class Square {
var side;
function constructor(length) {
side = length;
}
this.area = function () {
return side * side;
};
}
class Cube extends Square {
function constructor(side) {
uber(side);
}
this.area = function () {
return 6 * uber.area();
};
}
var cube = new Cube(5);
alert(cube.area());
Notice that the lines *ctor = constructor;
and return &uber;
have been removed. This is just redundant code necessary to make the constructor and inheritance work. Also the Class
function is not written in the source as it's automatically added by the transpiler.
The beauty of simulating pointers in JavaScript is demonstrated in the above program where the variable uber
in the class Cube
is initially the base class constructor function. However when it's called it's replaced by that instance of the base class which bees the prototype of this
.
It also means that an instance of Cube
will not be an instance of Square
unless and until the uber class constructor is called from Cube
.
本文标签: Is there a better way to simulate pointers in JavaScriptStack Overflow
版权声明:本文标题:Is there a better way to simulate pointers in JavaScript? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742081806a2419744.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论