{"id":353,"date":"2009-05-04T18:50:17","date_gmt":"2009-05-04T22:50:17","guid":{"rendered":"http:\/\/eligrey.com\/?p=353"},"modified":"2018-08-30T14:46:43","modified_gmt":"2018-08-30T21:46:43","slug":"namespacing-properties-in-javascript","status":"publish","type":"post","link":"https:\/\/eligrey.com\/blog\/namespacing-properties-in-javascript\/","title":{"rendered":"Namespacing properties in JavaScript"},"content":{"rendered":"<p>Namespacing properties is a great way to make a JavaScript library produce extendible objects. Namespacing in JavaScript can be done by prefixing <code><em>namespace<\/em>::<\/code> before object and property names. Unfortunately, namespacing is only supported in <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/New_in_JavaScript\/1.6\">JavaScript 1.6<\/a> and higher, which is currently only implemented in SpiderMonkey (Firefox&#8217;s JavaScript engine) and Rhino with <a href=\"https:\/\/developer.mozilla.org\/en\/E4X\">E4X<\/a> enabled. Namespaces should have a toString method that returns a string of the same name (<code>Foo.toString() == \"Foo\"<\/code>). In Firefox, the <code>@mozilla.org\/js\/function<\/code> namespace (&#8220;function&#8221;) seems to be the default at which everything is under. For example, <code>function::document == this.document<\/code> and <code>x = \"@mozilla.org\/js\/function\"; x::document == function::document<\/code>. Also, anything with a blank string representation behaves the same way as long as it&#8217;s being used in a property, for example:<\/p>\n<pre lang=\"javascript\">var foo = \"@mozilla.org\/js\/function\", bar = \"\";\r\ntry { \/\/ using try..catch because the error still fires in a typeof statement\r\n    foo::document; \/\/ works fine\r\n    bar::document; \/\/ error\r\n} catch(err if err instanceof ReferenceError) {\r\n    \/\/ err.message == \"reference to undefined XML name document\";\r\n}\r\nthis.bar::document == this.document;<\/pre>\n<p>The following example shows a naming conflict that can be solved using namespaced properties. In the examples, the fictional libraries, libSpaceTime and libDimensions are loaded. libDimensions adds a <code>Size<\/code> global and creates a &#8216;dimensions&#8217; setter on Object.prototype that accepts various inputs to change the width\/height\/depth\/ect. of something. libSpaceTime introduces the <code>SpaceTime<\/code> global. When a universe is created, the dimensions setter changes the number of dimensions the universe has. The width\/height\/ect. of a universe are automatically set (but can be changed) from the <code>matter<\/code> property.<br \/>\n<!--more--><\/p>\n<pre lang=\"javascript\">var foo = new SpaceTime.createUniverse({\r\n    dimensions: 4,\r\n    energy: 1.7976931348623158e+308,\r\n    matter: 130\r\n});\r\n\r\nfoo.dimensions = 5;\r\nObject.getOwnPropertyDescriptor(Object.prototype, \"dimensions\").set.call(foo, {width: 1});<\/pre>\n<p>In the example, it was impossible to use libDimensions&#8217; dimensions setter to change <code>foo<\/code> without using <code>Object.getOwnPropertyDescriptor(Object.prototype, \"dimensions\").set<\/code>. This is where namespacing properties can help. In the following example, all of the extra properties are namespaced to their global constructors, making property name collisions very unlikely. Assuming that the same original <code>foo<\/code> universe exists, the code would now be:<\/p>\n<pre lang=\"javascript\">foo.SpaceTime::dimensions = 5;\r\nfoo.Size::dimensions = {width: 1};<\/pre>\n<p>Another useful thing that works in conjunction with namespacing properties is using @-properties. For example, instead of using all the necessary methods to create a star, I could use the experimental createStar method that hasn&#8217;t been standardized yet, which would be accessible via <code>foo.@createStar()<\/code> if the library doesn&#8217;t namespace properties or <code>foo.@SpaceTime::createStar()<\/code> if the library does. This is easier to type than <code>foo.__createStar__()<\/code> and <code>foo.SpaceTime::__createStar__()<\/code>. About anywhere you start a property name with <code>_<\/code>, @ could be used instead. Of course, if your library is using E4X + XML, you should never do this due to @-properties being for XML tag attributes.<\/p>\n<p>If you would like to use namespaced properties in browsers that don&#8217;t support JavaScript 1.6 or higher, you could use a format like <code>object[n(namespace, property <em>[, useAtSign]<\/em>)]<\/code> where <code>n<\/code> is a function that returns the namespaced property name. I have created a simple reference function for this:<\/p>\n<pre lang=\"javascript\">function n\/*amespace*\/(ns, prop, at) {\r\n    return (at ? \"@\" : \"\") + ns + \"::\" + prop;\r\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Namespacing properties is a great way to make a JavaScript library produce extendible objects. Namespacing in JavaScript can be done by prefixing namespace:: before object and property names. Unfortunately, namespacing is only supported in JavaScript 1.6 and higher, which is currently only implemented in SpiderMonkey (Firefox&#8217;s JavaScript engine) and Rhino with E4X enabled. Namespaces should [&hellip;]<\/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":""},"categories":[1],"tags":[34,90,114],"class_list":["post-353","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-e4x","tag-javascript","tag-namespacing"],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pfpUD-5H","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/eligrey.com\/blog\/wp-json\/wp\/v2\/posts\/353","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eligrey.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eligrey.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eligrey.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/eligrey.com\/blog\/wp-json\/wp\/v2\/comments?post=353"}],"version-history":[{"count":0,"href":"https:\/\/eligrey.com\/blog\/wp-json\/wp\/v2\/posts\/353\/revisions"}],"wp:attachment":[{"href":"https:\/\/eligrey.com\/blog\/wp-json\/wp\/v2\/media?parent=353"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eligrey.com\/blog\/wp-json\/wp\/v2\/categories?post=353"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eligrey.com\/blog\/wp-json\/wp\/v2\/tags?post=353"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}