{"id":3129,"date":"2011-11-19T14:45:40","date_gmt":"2011-11-19T19:45:40","guid":{"rendered":"http:\/\/www.ericfeminella.com\/blog\/?p=3129"},"modified":"2016-03-30T14:42:51","modified_gmt":"2016-03-30T18:42:51","slug":"function-overwriting-in-javascript","status":"publish","type":"post","link":"https:\/\/www.ericfeminella.com\/blog\/2011\/11\/19\/function-overwriting-in-javascript\/","title":{"rendered":"Function Overwriting in JavaScript"},"content":{"rendered":"<p>Whether intentional, or simply a by-product of it&#8217;s design, Javascript, being a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Dynamic_programming_language\" target=\"_blank\">dynamic language<\/a>, allows for a level of expressiveness which most any seasoned programmer would come to appreciate. Javascript naturally provides the ability to implement some rather intriguing and quite unique patterns; one of which is the ability to overwrite a function at runtime.<\/p>\n<section>\n<h2>Function Overwriting<\/h2>\n<p><em>Function Overwriting<\/em> (also known as &#8220;Self-Defining Functions&#8221; or &#8220;Lazy Defining Functions&#8221;) provides a pattern which, as stated above, allows for overwriting a function&#8217;s definition at runtime. This can be accomplished from outside of the function, but also from within the function&#8217;s implementation itself.<\/p>\n<p>For example, on occasion a function may need to perform some initial piece of work, after which, all subsequent invocations would result in unnecessarily re-executing the initialization code. Typically, this issue is addressed by storing initialization flags or refactoring the initialization code to another function. While such a design solves this problem, it does result in unnecessary code which will need to be maintained. In JavaScript, perhaps a different approach is in order: we can simply redefine the function after the initialization work has been completed.<\/p>\n<p>A possible candidate use-case for Function Overwriting is Feature Detection as, detecting for specific feature support in the Browser typically only needs to be tested once, at which point subsequent tests are unnecessary. <\/p>\n<p>Below is a basic example of implementing <em>Function Overwritting<\/em> in the context of an abstraction of the <a href=\"http:\/\/dev.w3.org\/geo\/api\/spec-source.html\" title=\"HTML5 Geolocation\" target=\"_blank\">HTML5 Geolocation<\/a> API.<\/p>\n<pre lang=\"javascript\">\r\n\/\/ Initial \"getLocation\" implementation. Since we only need to test\r\n\/\/ for Geolocation support once, we perform the initial test and then\r\n\/\/ overwrite the \"getLocation\" implementation based on the results of\r\n\/\/ the test.\r\nvar getLocation = function(success, fail, options) {\r\n  if (navigator.geolocation) {\r\n    var _options = {\r\n      enableHighAccuracy: true,\r\n      timeout: 60000,\r\n      maximumAge: 0\r\n    };\r\n\r\n    \/\/ Geolocation is supported, so we overwrite the implementation\r\n    \/\/ to simply invoke \"geolocation.getCurrentPosition\" as there \r\n    \/\/ is no need to perform the test again.\r\n    getLocation = function(success, fail, options) {\r\n      geolocation.getCurrentPosition(success,\r\n        fail,\r\n        options || _options);\r\n    }\r\n    getLocation(success, fail, options);\r\n  } else {\r\n    \/\/ Geolocation is not supported, so we overwrite the \r\n    \/\/ implementation to simply return false (a real \r\n    \/\/ implementation might provide a polyfill here...).\r\n    getLocation = function() {\r\n      return false;\r\n    }\r\n  }\r\n};\r\n<\/pre>\n<\/section>\n<section>\n<h2>Considerations<\/h2>\n<p>Since functions are objects in Javascript, it is important to keep in mind that if you add a property or method to a function (either statically or via the function&#8217;s prototype), and then overwrite the function, you will have effectively removed those properties or methods as well. Also, if the function is referenced by another variable, or by a method of another object, the initially defined implementation will be preserved and the overwriting process will not occur. As such, be mindful when implementing this pattern. As a general rule of thumb, I typically only implement Function Overwriting when the function being redefined is in a private scope.<br \/>\n<\/section>\n<section>\n<h2>Concluding Thoughts<\/h2>\n<p>As you can see, Function Overwriting provides a convenient facility for optimizing code execution at runtime. There are many use-cases for dynamically overwriting functions and, where appropriate, they can certainly provide value in terms of performance and code maintainability. <\/p>\n<p>Below you can find an example which demonstrates two basic <em>Function Overwriting<\/em> implementations. Simply load the page and add some breakpoints in Firebug to test the execution paths; both before and after overwriting each function occurs, or you can simply view the source.<br \/>\n<a href=\"http:\/\/code.ericfeminella.com\/articles\/examples\/js\/function-overwritting\/\" title=\"Function Overwriting Example\" target=\"_blank\">Example<\/a><br \/>\n<\/section>\n","protected":false},"excerpt":{"rendered":"<p>Whether intentional, or simply a by-product of it&#8217;s design, Javascript, being a dynamic language, allows for a level of expressiveness which most any seasoned programmer would come to appreciate. Javascript naturally provides the ability to implement some rather intriguing and quite unique patterns; one of which is the ability to overwrite a function at runtime. Function Overwriting Function Overwriting (also&#8230; <a class=\"read-more\" href=\"https:\/\/www.ericfeminella.com\/blog\/2011\/11\/19\/function-overwriting-in-javascript\/\">Continue Reading<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","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":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[133,23,59,78,31,45],"tags":[168,65,68],"class_list":["post-3129","post","type-post","status-publish","format-standard","hentry","category-browsers","category-design-patterns","category-html5","category-javascript-2","category-oop","category-refactoring","tag-design-patterns-2","tag-html5-2","tag-javascript"],"jetpack_publicize_connections":[],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.ericfeminella.com\/blog\/wp-json\/wp\/v2\/posts\/3129","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ericfeminella.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ericfeminella.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ericfeminella.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ericfeminella.com\/blog\/wp-json\/wp\/v2\/comments?post=3129"}],"version-history":[{"count":0,"href":"https:\/\/www.ericfeminella.com\/blog\/wp-json\/wp\/v2\/posts\/3129\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.ericfeminella.com\/blog\/wp-json\/wp\/v2\/media?parent=3129"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ericfeminella.com\/blog\/wp-json\/wp\/v2\/categories?post=3129"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ericfeminella.com\/blog\/wp-json\/wp\/v2\/tags?post=3129"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}