Tuesday, July 17, 2012

Function.prototype.toString()

Not a lot new in the fn.toString() area. After reading through the latest Spec and the es-discuss thread on the topic, I understood a few things about Function.prototype.toString that I can impart.

Before I mention any changes, I should inform everyone that Function.prototype.toString already existed in the ES spec. It isn't new to ES6. If you haven't ever used it, go ahead and try it out now. Open your console or your scratchpad and try it. If you like. However, there may be a few things that I can tell you about this functionality.

An interesting fact here: none of the browsers implemented Function.prototype.toString the way that the ES3 and ES5 spec said to. They all did it a different way. So, rather than have everyone change their implementation, they altered the spec to match the current functionality (plus a few changelets). Now we can rest assured that the spec and the functionality match. 

Function Declaration vs Function Expression
Below you will see two functions. They are almost identical. The main difference is that the first one is a Function Declaration, and the second one is a Function Expression. 

    function test1(){
        console.log("This is test1 function");
    }

    var test2 = function(){
        console.log("This is test2 function");
    }



It is fairly obvious what will happen when these methods are called. However calling toString on them will be very different. Look at what we end up with when we call toString on our functions:

    console.log(test1.toString());
        "function test1(){
            console.log('This is test1 function');
        }"

    console.log(test1.toString());
        "function (){
            console.log('This is test2 function');
        }"
Please notice that test1 resulted in a complete implementation, while test2 merely resulted in an anonymous function string. At this point, if we were to eval()uate them, we would have completely different results.

eval(test1)
Calling eval(test1.toString()) at this point would bind a the test1 function to the current scope.

eval(test2)
Calling eval(test2.toString()) at this point will cause a syntax error. In order to get this to work, you would have to do the following: eval("var newfunction = "+test2.toString()). If you append a variable declaration (or rather the string representation of a variable declaration) and THEN eval()uate, everything works fine. Your eval will bind the function to the current scope without any errors.

etc
Other pieces worth mentioning:

  • This will be covered with much more detail in the book. 
  • native functions will return an unusable string, something like: "[native code]"
  • Calling the Function.prototype.toString on a non-function throws an error, ie: Function.prototype.toString.call(123) will throw an error since the number 123 is not a function. 
  • The previous versions of the spec said that Function.prototype.toString should return a Function Declaration compliant string. However, the major browser vendors implemented the aforementioned functionality, making Function Declarations return FD implemented strings, and Function Expressions return anonymous function implemented strings.  
Please message me if there are questions. Also, if I made any mistakes, please add comments to correct me. Thanks!

No comments:

Post a Comment