{"id":149,"date":"2007-01-03T23:20:32","date_gmt":"2007-01-04T03:20:32","guid":{"rendered":"http:\/\/benjamin.smedbergs.us\/blog\/2007-01-03\/bound-functions-and-function-imports-in-javascript\/"},"modified":"2007-01-03T23:20:32","modified_gmt":"2007-01-04T03:20:32","slug":"bound-functions-and-function-imports-in-javascript","status":"publish","type":"post","link":"http:\/\/benjamin.smedbergs.us\/blog\/2007-01-03\/bound-functions-and-function-imports-in-javascript\/","title":{"rendered":"Bound Functions and Function Imports in JavaScript"},"content":{"rendered":"<p>After playing with <a href=\"http:\/\/benjamin.smedbergs.us\/blog\/2006-12-22\/simplifying-xpcom-code-patterns\/\">the code in my last post<\/a>, and <a href=\"http:\/\/groups.google.com\/group\/mozilla.dev.tech.js-engine\/browse_frm\/thread\/765ab3ac516ea553\/ad7b5e54f1ffc301#ad7b5e54f1ffc301\">asking some apparently silly questions about the ES4 spec<\/a>, I&#8217;ve found some techniques which can be used to implement python-style &#8220;import&#8221; using current JavaScript.<\/p>\n<h4>References to Bound Functions<\/h4>\n<p>In python, it is possible to hold a reference to an unbound method, or to a method which is bound to a particular object:<\/p>\n<pre class=\"code\">>>>class Foo:\r\n...  def dumpMe(self, arg):\r\n...    print \"self: %s\\narg: %s\" % (self, arg)\r\n...\r\n>>> Foo.dumpMe\r\n<em>&lt;unbound method Foo.dumpMe&gt;<\/em>\r\n>>> Foo().dumpMe\r\n<em>&lt;bound method Foo.dumpMe of &lt;__main__.Foo instance at 0x2aaaaab33680&gt;&gt;<\/em>\r\n>>> Foo.dumpMe(\"something\")\r\n<em>Traceback (most recent call last):\r\n  File \"&lt;stdin&gt;\", line 1, in ?\r\nTypeError: unbound method dumpMe() must be called with Foo instance as first argument (got str instance instead)<\/em>\r\n>>> Foo().dumpMe(\"something\")\r\n<em>self: &lt;__main__.Foo instance at 0x2aaaaab33d40&gt;\r\narg: something<\/em><\/pre>\n<p>The JavaScript language does not have a built-in syntax to obtain a bound method:<\/p>\n<pre class=\"code\">js> function Foo() { }\r\njs&gt; Foo.prototype.dumpMe = function(arg) {\r\n  dump(\"this: \" + this + \"\\narg: \" + arg);\r\n}\r\njs&gt; new Foo().dumpMe\r\n<em>function (arg) {\r\n    print(\"this: \" + this + \"\\narg: \" + arg);\r\n}<\/em>\r\njs&gt; f = new Foo();\r\njs&gt; f.dumpMe(\"test\")\r\n<em>this: [object Object]\r\narg: test<\/em>\r\njs&gt; unbound = new Foo().dumpMe\r\njs&gt; unbound(\"test\")\r\n<em>this: [object BackstagePass @ 0x6214e0 (native @ 0x513fc8)]\r\narg: test<\/em>\r\n<\/pre>\n<p>(The BackstagePass object is the global object in xpcshell).<\/p>\n<p>However, with a little extra code it is possible to emulate bound functions in JavaScript:<\/p>\n<pre class=\"code\">js&gt; Function.prototype.bind = function(object) {\r\n  var func = this;\r\n  return function() { return func.apply(object, arguments); }\r\n}\r\njs&gt; boundFunc = f.dumpMe.bind(f);\r\njs&gt; boundFunc(\"test\")\r\n<em>this: [object Object]\r\narg: test<\/em><\/pre>\n<p>We can then use bound functions to emulate the <tt>from module import x, y, x<\/tt> statement of python:<\/p>\n<pre class=\"code\">js&gt; function jsimport(module) {\r\n  \/\/ this function has two forms:\r\n  \/\/ jsimport(module) is equivalent to python \"from module import *\"\r\n  \/\/ jsimport(module, \"name\" [, \"name2\"]) is equivalent to python \"from module import name, name2\"\r\n\r\n  \/\/ NOTE: \"this\" is the global object\r\n  function internal_import(name) {\r\n    if (module[name] instanceof Function) {\r\n      this[name] = module[name].bind(module);\r\n    }\r\n    else {\r\n      this[name] = module[name];\r\n    }\r\n  }\r\n\r\n  if (arguments.length == 1) {\r\n    for (name in module) {\r\n      if (module.hasOwnProperty(name)) {\r\n        internal_import(name);\r\n      }\r\n    }\r\n  }\r\n  else {\r\n    for (i = 1; i < arguments.length; ++i) {\r\n      internal_import(arguments[i]);\r\n    }\r\n  }\r\n}\r\n<\/pre>\n<p>You could use this technique today to hide away the IOService or PrefService a little:<\/p>\n<pre class=\"code\">jsimport(Components.classes[\"@mozilla.org\/preferences\/pref-service;1\"].getService(Components.interfaces.nsIPrefBranch),\r\n         \"getCharPref\", \"getIntPref\", \"getBoolPref\");\r\n\r\nif (getBoolPref(\"dom.window.dump.enabled\"))\r\n  \/\/ do something dumpy<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>After playing with the code in my last post, and asking some apparently silly questions about the ES4 spec, I&#8217;ve found some techniques which can be used to implement python-style &#8220;import&#8221; using current JavaScript. References to Bound Functions In python, it is possible to hold a reference to an unbound method, or to a method [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[39,32,38],"class_list":["post-149","post","type-post","status-publish","format-standard","hentry","category-mozilla","tag-javascript","tag-python","tag-xpcom"],"_links":{"self":[{"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/posts\/149","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/comments?post=149"}],"version-history":[{"count":0,"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/posts\/149\/revisions"}],"wp:attachment":[{"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/media?parent=149"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/categories?post=149"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/benjamin.smedbergs.us\/blog\/wp-json\/wp\/v2\/tags?post=149"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}