{"id":621,"date":"2012-11-24T18:35:19","date_gmt":"2012-11-24T13:05:19","guid":{"rendered":"http:\/\/ramkulkarni.com\/blog\/?p=621"},"modified":"2012-11-24T18:35:19","modified_gmt":"2012-11-24T13:05:19","slug":"getset-local-variables-of-javascript-function-from-outside-dynamic-code-insertion-in-js-function","status":"publish","type":"post","link":"http:\/\/ramkulkarni.com\/blog\/getset-local-variables-of-javascript-function-from-outside-dynamic-code-insertion-in-js-function\/","title":{"rendered":"Get\/Set local variables of JavaScript function from outside &amp; Dynamic code insertion in JS function"},"content":{"rendered":"<p>I am working on a JavaScript framework that needs to get list of local function variables and set values of some of them. Unlike Java, JavaScript does not have runtime introspection<br \/>\nsupport. In Java you can do this using Java Reflection APIs, but I couldn&#8217;t think of any way to do this in JavaScript. So I searched on the web and came across two threads of discussions on StackOverflow &#8211;<\/p>\n<ul>\n<li><a href=\"http:\/\/stackoverflow.com\/questions\/2336508\/javascript-get-access-to-local-variable-or-variable-in-closure-by-its-name\" target=\"_blank\">http:\/\/stackoverflow.com\/questions\/2336508\/javascript-get-access-to-local-variable-or-variable-in-closure-by-its-name<\/a><\/li>\n<li><a href=\"http:\/\/stackoverflow.com\/questions\/9134686\/adding-code-to-a-javascript-function-programatically\" target=\"_blank\">http:\/\/stackoverflow.com\/questions\/9134686\/adding-code-to-a-javascript-function-programatically<\/a><\/li>\n<\/ul>\n<p>There are some interesting solutions discussed in the above threads. The first one discusses solutions for setting local variable values. The second one interested me because I found the technique useful for injecting code (that will set local variable value) in a function.<\/p>\n<p><!--more--><\/p>\n<p>However they do not directly provide solution for getting local variables in a JS function from outside it. But I was able to come up with a solution for this. The scenario for which I have posted the code below is this &#8211; a function, let&#8217;s call it &#8216;test&#8217;, declares a few local variables, prints value of a variable before it calls a framework function (which gets local variables declared in the &#8216;test&#8217; function and changes value of a variable) and then prints the value of the same variable (after it has been changed by the framework function). Here is the complete solution\/code &#8211;<\/p>\n<pre style=\"color: #000000; background: #ffffff;\">&lt;script language=<span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">JavaScript<\/span><span style=\"color: #2a00ff;\">\"<\/span>&gt;\n<span style=\"color: #3f7f59;\">\/\/Instrument local functions for the framework<\/span>\ninstrumentFunctions();\n\n<span style=\"color: #3f7f59;\">\/**<\/span>\n<span style=\"color: #3f7f59;\">\u00a0* Test function.<\/span>\n<span style=\"color: #3f7f59;\">\u00a0* We will get all local variables in this function and set value of a local variable<\/span>\n<span style=\"color: #3f7f59;\">\u00a0*\/<\/span>\n<span style=\"color: #7f0055; font-weight: bold;\">function<\/span> <span style=\"color: #7f0055; font-weight: bold;\">test<\/span>()\n{\n    <span style=\"color: #3f7f59;\">\/\/Declare some local variables<\/span>\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> i = 100;\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span>  j = 10, k = 20;\n\n    <span style=\"color: #3f7f59;\">\/\/Print value of i before it is changed by our framework<\/span>\n    console.<span style=\"color: #7f0055; font-weight: bold;\">log<\/span>(<span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\"> i = <\/span><span style=\"color: #2a00ff;\">\"<\/span> + i);\n    document.writeln(<span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">Before framework call, i = <\/span><span style=\"color: #2a00ff;\">\"<\/span> + i + <span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">&lt;br&gt;<\/span><span style=\"color: #2a00ff;\">\"<\/span>);\n\n    <span style=\"color: #3f7f59;\">\/\/Call a framework specific function. <\/span>\n    <span style=\"color: #3f7f59;\">\/\/For this example, we will change value of i in the framework function<\/span>\n    <span style=\"color: #7f0055; font-weight: bold;\">if<\/span> (<span style=\"color: #7f0055; font-weight: bold;\">typeof<\/span> __ctx != <span style=\"color: #2a00ff;\">'undefined'<\/span>)\n        someFrameworkFunction(__ctx);\n\n    <span style=\"color: #3f7f59;\">\/\/Print value of i after calling framework function <\/span>\n    console.<span style=\"color: #7f0055; font-weight: bold;\">log<\/span>(<span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\"> i = <\/span><span style=\"color: #2a00ff;\">\"<\/span> + i);\n    document.writeln(<span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">After framework call, i = <\/span><span style=\"color: #2a00ff;\">\"<\/span> + i + <span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">&lt;br&gt;<\/span><span style=\"color: #2a00ff;\">\"<\/span>);\n}\n\n<span style=\"color: #3f7f59;\">\/**<\/span>\n<span style=\"color: #3f7f59;\">\u00a0* Some framework function that is expected to work with local variables declared in the <\/span>\n<span style=\"color: #3f7f59;\">\u00a0* function from which it is called.<\/span>\n<span style=\"color: #3f7f59;\">\u00a0* <\/span>\n<span style=\"color: #3f7f59;\">\u00a0* @param {Object} ctx - context object that has reference to caller and code injected by instrumentFunc function<\/span>\n<span style=\"color: #3f7f59;\">\u00a0*\/<\/span>\n<span style=\"color: #7f0055; font-weight: bold;\">function<\/span> someFrameworkFunction(ctx)\n{\n    <span style=\"color: #3f7f59;\">\/\/Assume this is some framework function that needs to access<\/span>\n    <span style=\"color: #3f7f59;\">\/\/and set local variables of calling function.<\/span>\n\n    <span style=\"color: #3f7f59;\">\/\/Get list of local variables in a function from which this function is called<\/span>\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> localVars = ctx.getLocalVars();\n    <span style=\"color: #3f7f59;\">\/\/Print local variables<\/span>\n    document.writeln(<span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">Local variables in <\/span><span style=\"color: #2a00ff;\">\"<\/span> + ctx.caller.name + <span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\"> : <\/span><span style=\"color: #2a00ff;\">\"<\/span> + localVars.<span style=\"color: #7f0055; font-weight: bold;\">toString<\/span>() + <span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">&lt;br&gt;<\/span><span style=\"color: #2a00ff;\">\"<\/span>);\n\n    <span style=\"color: #3f7f59;\">\/\/Change value of local variable i <\/span>\n    ctx.set(<span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">i<\/span><span style=\"color: #2a00ff;\">\"<\/span>, 300);\n}\n\n<span style=\"color: #3f7f59;\">\/**<\/span>\n<span style=\"color: #3f7f59;\">\u00a0* Calls instrumentFunction method for functions that need to be instrumented<\/span>\n<span style=\"color: #3f7f59;\">\u00a0*\/<\/span>\n<span style=\"color: #7f0055; font-weight: bold;\">function<\/span> instrumentFunctions()\n{\n    <span style=\"color: #3f7f59;\">\/\/Instrument all functions that you want to be accessed by the framework<\/span>\n    instrumentFunc(<span style=\"color: #7f0055; font-weight: bold;\">test<\/span>);\n}\n\n<span style=\"color: #3f7f59;\">\/**<\/span>\n<span style=\"color: #3f7f59;\">\u00a0* Inserts code in the given function to set local variable and get list of local variables<\/span>\n<span style=\"color: #3f7f59;\">\u00a0* <\/span>\n<span style=\"color: #3f7f59;\">\u00a0* @param {Function} func - Function in which to insert framework specific code <\/span>\n<span style=\"color: #3f7f59;\">\u00a0*\/<\/span>\n<span style=\"color: #7f0055; font-weight: bold;\">function<\/span> instrumentFunc(func)\n{\n    <span style=\"color: #7f0055; font-weight: bold;\">if<\/span> (<span style=\"color: #7f0055; font-weight: bold;\">typeof<\/span> func != <span style=\"color: #2a00ff;\">'function'<\/span>)\n        <span style=\"color: #7f0055; font-weight: bold;\">return<\/span>;\n\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> oldCode = func.<span style=\"color: #7f0055; font-weight: bold;\">toString<\/span>();\n\n    <span style=\"color: #3f7f59;\">\/\/We want to insert code in the function just after opening '{'<\/span>\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> index = oldCode.<span style=\"color: #7f0055; font-weight: bold;\">indexOf<\/span>(<span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">{<\/span><span style=\"color: #2a00ff;\">\"<\/span>);\n\n    <span style=\"color: #3f7f59;\">\/\/Split code, part before and after opening '{'<\/span>\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> oldCodePart1 = oldCode.<span style=\"color: #7f0055; font-weight: bold;\">slice<\/span>(0,index+1);\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> oldCodePart2 = oldCode.<span style=\"color: #7f0055; font-weight: bold;\">slice<\/span>(index+1);\n\n    <span style=\"color: #3f7f59;\">\/\/We will create a context object and create keys to set and get local variables.<\/span>\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> codeToInsert = <span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">var __ctx = {}; __ctx.caller=arguments.callee;__ctx.variables={};__ctx.set = __setVar;<\/span><span style=\"color: #2a00ff;\">\"<\/span>;\n\n    <span style=\"color: #3f7f59;\">\/\/setVar function declaration<\/span>\n    codeToInsert += <span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">function __setVar(name, value){try{eval(name);} catch (err){return false;}eval(name + <\/span><span style=\"color: #2a00ff;\">\\\"<\/span><span style=\"color: #2a00ff;\"> = <\/span><span style=\"color: #2a00ff;\">\\\"<\/span><span style=\"color: #2a00ff;\"> + value);return true;};<\/span><span style=\"color: #2a00ff;\">\"<\/span>;\n    codeToInsert += <span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">__ctx.getLocalVars = __getLocalVars;<\/span><span style=\"color: #2a00ff;\">\"<\/span>\n\n    <span style=\"color: #3f7f59;\">\/\/setLocalVars function declaration<\/span>\n    codeToInsert += <span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">function __getLocalVars(){return getLocalVarNames(__ctx.caller.toString());};<\/span><span style=\"color: #2a00ff;\">\"<\/span>\n\n    <span style=\"color: #3f7f59;\">\/\/New function code<\/span>\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> newCode = oldCodePart1 + codeToInsert + oldCodePart2;\n\n    <span style=\"color: #3f7f59;\">\/\/Create new function<\/span>\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> newFunc = <span style=\"color: #7f0055; font-weight: bold;\">eval<\/span>(<span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">newCode<\/span><span style=\"color: #2a00ff;\">\"<\/span>);\n\n    <span style=\"color: #3f7f59;\">\/\/Replace old function<\/span>\n    <span style=\"color: #7f0055; font-weight: bold;\">eval<\/span> (<span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">window.<\/span><span style=\"color: #2a00ff;\">\"<\/span> + func.name + <span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\"> = <\/span><span style=\"color: #2a00ff;\">\"<\/span> + newFunc);\n}\n\n<span style=\"color: #3f7f59;\">\/**<\/span>\n<span style=\"color: #3f7f59;\">\u00a0* Gets local variables, declared with var keyword in the given code<\/span>\n<span style=\"color: #3f7f59;\">\u00a0* <\/span>\n<span style=\"color: #3f7f59;\">\u00a0* @param {String} code - JS code<\/span>\n<span style=\"color: #3f7f59;\">\u00a0* <\/span>\n<span style=\"color: #3f7f59;\">\u00a0* @returns Array of local variable names<\/span>\n<span style=\"color: #3f7f59;\">\u00a0*\/<\/span>\n<span style=\"color: #7f0055; font-weight: bold;\">function<\/span> getLocalVarNames (code)\n{\n    <span style=\"color: #3f7f59;\">\/\/Find variables declared as var, i.e. local variables in the given code<\/span>\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> regex <span style=\"color: #2a00ff;\">=<\/span><span style=\"color: #2a00ff;\">\/<\/span><span style=\"color: #7f0055; font-weight: bold;\">\\b<\/span><span style=\"color: #2a00ff;\">var<\/span><span style=\"color: #7f0055; font-weight: bold;\">\\b<\/span><span style=\"color: #2a00ff;\">\\s<\/span><span style=\"color: #2a00ff;\">*<\/span><span style=\"color: #2a00ff;\">(<\/span><span style=\"color: #2a00ff; font-weight: bold;\">?<\/span><span style=\"color: #2a00ff; font-weight: bold;\">:<\/span><span style=\"color: #2a00ff;\">\\s<\/span><span style=\"color: #2a00ff;\">*<\/span><span style=\"color: #2a00ff;\">(<\/span><span style=\"color: #2a00ff;\">\\w<\/span><span style=\"color: #2a00ff;\">+<\/span><span style=\"color: #2a00ff;\">)<\/span><span style=\"color: #2a00ff;\">\\s<\/span><span style=\"color: #2a00ff;\">*(?:<\/span><span style=\"color: #2a00ff;\">=<\/span><span style=\"color: #2a00ff;\">[<\/span><span style=\"color: #2a00ff;\">^<\/span><span style=\"color: #2a00ff;\">,;<\/span><span style=\"color: #2a00ff;\">]<\/span><span style=\"color: #2a00ff;\">+)?<\/span><span style=\"color: #2a00ff;\">)<\/span><span style=\"color: #2a00ff;\">(<\/span><span style=\"color: #2a00ff; font-weight: bold;\">?<\/span><span style=\"color: #2a00ff; font-weight: bold;\">:<\/span><span style=\"color: #2a00ff;\">\\s<\/span><span style=\"color: #2a00ff;\">*<\/span><span style=\"color: #2a00ff;\">,<\/span><span style=\"color: #2a00ff;\">\\s<\/span><span style=\"color: #2a00ff;\">*<\/span><span style=\"color: #2a00ff;\">(<\/span><span style=\"color: #2a00ff;\">\\w<\/span><span style=\"color: #2a00ff;\">+<\/span><span style=\"color: #2a00ff;\">)<\/span><span style=\"color: #2a00ff;\">\\s<\/span><span style=\"color: #2a00ff;\">*(?:<\/span><span style=\"color: #2a00ff;\">=<\/span><span style=\"color: #2a00ff;\">[<\/span><span style=\"color: #2a00ff;\">^<\/span><span style=\"color: #2a00ff;\">,;<\/span><span style=\"color: #2a00ff;\">]<\/span><span style=\"color: #2a00ff;\">+<\/span><span style=\"color: #2a00ff;\">)?)<\/span><span style=\"color: #2a00ff;\">*<\/span><span style=\"color: #2a00ff;\">\\s<\/span><span style=\"color: #2a00ff;\">*<\/span><span style=\"color: #2a00ff;\">;<\/span><span style=\"color: #2a00ff;\">\/<\/span><span style=\"color: #7f0055; font-weight: bold;\">g<\/span>;\n    <span style=\"color: #7f0055; font-weight: bold;\">var<\/span> matches, result = [];\n    <span style=\"color: #7f0055; font-weight: bold;\">while<\/span> (matches = regex.<span style=\"color: #7f0055; font-weight: bold;\">exec<\/span>(code))\n    {\n        <span style=\"color: #7f0055; font-weight: bold;\">for<\/span> (<span style=\"color: #7f0055; font-weight: bold;\">var<\/span> i = 1; i &lt; matches.length; i++) {\n            <span style=\"color: #7f0055; font-weight: bold;\">if<\/span> (matches[i] != undefined) {\n                <span style=\"color: #3f7f59;\">\/\/filter framework specific variables here<\/span>\n                <span style=\"color: #7f0055; font-weight: bold;\">if<\/span> (matches[i] != <span style=\"color: #2a00ff;\">\"<\/span><span style=\"color: #2a00ff;\">__ctx<\/span><span style=\"color: #2a00ff;\">\"<\/span>)\n                    result.push(matches[i]);\n            }\n        }\n    }\n    <span style=\"color: #7f0055; font-weight: bold;\">return<\/span> result;\n}\n\n<span style=\"color: #3f7f59;\">\/\/Call test function. This function is already instrumented in instrumentFunctions<\/span>\n<span style=\"color: #7f0055; font-weight: bold;\">test<\/span>();\n\n&lt;\/script&gt;<\/pre>\n<p>-Ram Kulkarni<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I am working on a JavaScript framework that needs to get list of local function variables and set values of some of them. Unlike Java, JavaScript does not have runtime introspection support. In Java you can do this using Java Reflection APIs, but I couldn&#8217;t think of any way to do this in JavaScript. So &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/ramkulkarni.com\/blog\/getset-local-variables-of-javascript-function-from-outside-dynamic-code-insertion-in-js-function\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Get\/Set local variables of JavaScript function from outside &amp; Dynamic code insertion in JS function&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[20,1],"tags":[59,60,5],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2g9O8-a1","jetpack-related-posts":[],"_links":{"self":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/621"}],"collection":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/comments?post=621"}],"version-history":[{"count":0,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/621\/revisions"}],"wp:attachment":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/media?parent=621"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/categories?post=621"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/tags?post=621"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}