|
Page 1 of 2
When programming was a young subject and valves ruled the earth a very powerful but very scary technique was invented – self-modifying code.
The whole beauty of the stored program computer design was that the data and program were treated in the same way. A program plus the data it needed to work with were loaded into memory and the program simply accessed and modified the data as required.
This idea was so new and powerful that programmers often didn’t really distinguish between the program and the data and allowed one part of the program to modify another part of the program.
Self-modifying code can effectively re-write itself as it runs and as such you can guess that it’s powerful but you should also be able to see that it creates a nightmare for debugging and generally understanding what is going on.
After all, if code is self modifying, there is no simple static piece of code that can be read through to check it makes sense.
As a result self-modifying code not only fell out of favour, it was actively demonised as something that only really evil programming languages would allow you to do. So if you think that self-modifying code has just been invented and is something connected with the new wave of dynamic languages think again – it’s old but still relatively untamed.
After all of this you might be surprised to learn that JavaScript allows self-modifying code. Indeed most interpreted or dynamic languages do. The point being that self modification isn’t always bad – you just need to work hard to keep it under control and that means keep it simple.
Dynamic functions - function to string
The reason why JavaScript supports runtime modifiable code is that the program itself is just data stored in a variable. Consider the way you can define a function:
function Myfunc1(){alert("MyFunc 1");
which is almost exactly equivalent to:
MyFunc1=function(){alert("My Func 1")};
The second form looks like a variable assignment and indeed it is. If you don’t believe me try:
alert(MyFunc1);
and you will see the text of the function just as if it was a string. However MyFunc1 isn’t actually a string – it’s a Function object. What is going on here is that the Function’s toString method is being called and this returns a string representation of the function:
alert(MyFunc1.toString());
Although this isn’t guaranteed, it works in all the major browsers.
There is also a rather more non-standard method called toSource which works in Firefox but not Explorer. Also notice that you can’t see the source code for internally defined functions only user defined functions.
You can take a function and convert it into a string using:
MyString=MyFunc1.toString(); alert(MyString);
or you can use the String object’s constructor and an implied call to the toString method:
MyString=new String(MyFunc1);
Of course now that you have the function represented as a string you can edit it in any way that you like.
For example, you can change the “1” into a “2” using:
MyString=MyString.replace("1","2"); alert(MyString);
This changes what is stored in the string into:
function(){alert("My Func 2")};
Notice that this is a string and there is no way you can directly execute this new function, i.e.
MyString();
doesn’t do anything.
The round trip - string to function
The real question is how to get the string back into a function and there are a number of ways of doing this.
The most direct is to use the Function object’s constructor. If you write:
MyFunc=new Function(“arg1”, “arg2” … “statements”);
the new function will be created with the specified arguments and statements. Notice that the number of arguments can't be variable as the last string passed to the constructor is taken to be the body of the new function.
To use this with our string we simply have to strip off the “function()” part of the string. Unfortunately some browsers place a space between “function” and “()” and some don’t.
You can probably improve on this implementation of the constructor:
MyFunc2=new Function( MyString.replace("function()","") .replace("function ()","")); MyFunc2();
Notice that there are no parameters used in this function and writing a routine to convert any function in the form of a string into a real function is slightly more difficult.
Fortunately there is an easier method based on using eval.
The eval function accepts a string of JavaScript statements and executes them as if they were within your program. So to convert a string to a function you simply use:
eval("MyFunc2="+MyString1); alert(MyFunc2);
This completes the “round-trip” in the sense that you can now convert a function to a string, modify it and convert it back to a function.
This gives you the power to write self-modifying code of arbitrary complexity and the same tricks can be used to modify object methods just as easily.
<ASIN:0470684143>
<ASIN:0137054890>
<ASIN:0470526912>
<ASIN:1449381871>
<ASIN:1430230541>
<ASIN:0321683919>
|