{"id":28,"date":"2008-08-05T00:44:48","date_gmt":"2008-08-05T06:44:48","guid":{"rendered":"http:\/\/bililite.nfshost.com\/blog\/index.php\/2008\/08\/05\/namespaces-in-jquery\/"},"modified":"2008-08-12T01:34:54","modified_gmt":"2008-08-12T07:34:54","slug":"namespaces-in-jquery","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2008\/08\/05\/namespaces-in-jquery\/","title":{"rendered":"Namespaces in jQuery"},"content":{"rendered":"<p>jQuery encourages using namespaces for methods in the <code class=\"language-javascript\">$<\/code> namespace, like <code class=\"language-javascript\">$.foo.bar()<\/code> rather than <code class=\"language-javascript\">$.bar()<\/code>. This works for <code class=\"language-javascript\">$<\/code> because methods don't expect <code class=\"language-javascript\">this<\/code> to refer to anything specific, and the way javascript works is to assign <code class=\"language-javascript\">this<\/code> to the last-named object, so in <code class=\"language-javascript\">$.foo.bar()<\/code>, <code class=\"language-javascript\">this<\/code> refers to <code class=\"language-javascript\">$.foo<\/code>.<\/p>\r\n<p>This idea fails for plugins, however, since plugins expect <code class=\"language-javascript\">this<\/code> to refer to the jQuery object that started the chain.\r\nIf I define <code class=\"language-javascript\">$.fn.bar = function(){}<\/code>, then when <code class=\"language-javascript\">$(...).bar()<\/code> is called, <code class=\"language-javascript\">this<\/code> refers to <code class=\"language-javascript\">$(...)<\/code>, just as we want. But if I define <code class=\"language-javascript\">$.fn.foo.bar = function(){}<\/code>, then when <code class=\"language-javascript\">$(...).foo.bar()<\/code> is called, <code class=\"language-javascript\">this<\/code> refers to <code class=\"language-javascript\">$(...).foo<\/code>, which is an object that knows nothing about jQuery. There's no way to make an object reference return something else.<\/p>\r\n<p>But all is not lost. We can define a function that returns an object, and that function can use <code class=\"language-javascript\">this<\/code> to set the returned object to be just like a jQuery object, but with the desired namespaced methods in it. The inefficient way to do that is to copy the new methods into the jQuery object, but if we can manipulate the prototype chain directly (as we can in Firefox) we can add our new methods to the chain without copying.<\/p>\r\n<!--more-->\r\n<p>So a namespacing plugin would be:<\/p>\r\n<pre><code class=\"language-javascript\">\r\n(function($){\r\nif ({}.__proto__){\r\n\t\/\/ mozilla  & webkit expose the prototype chain directly\r\n\t$.namespace = function(name){\r\n\t\t$.fn[name] = function namespace() { \/\/ insert this function in the prototype chain\r\n\t\t\tthis.__proto__ = arguments.callee;\r\n\t\t\treturn this;\r\n\t\t};\r\n\t\t$.fn[name].__proto__ = $.fn;\r\n\t};\r\n\t$.fn.$ = function(){\r\n\t\tthis.__proto__ = $.fn;\r\n\t\treturn this;\r\n\t};\t\r\n}else{\r\n\t\/\/ every other browser; need to copy methods\r\n\t$.namespace = function(name){\r\n\t\t$.fn[name] = function namespace() { return this.extend(arguments.callee); };\r\n\t};\r\n\t$.fn.$ = function() { \/\/ slow but restores the default namespace\r\n\t\tvar len = this.length;\r\n\t\tthis.extend($.fn);\r\n\t\tthis.length = len; \/\/ $.fn has length = 0, which messes everything up\r\n\t\treturn this;\r\n\t};\r\n}\r\n})(jQuery);\r\n<\/code><\/pre>\r\n<p>And you could use it like:<\/p>\r\n<pre><code class=\"language-javascript\">\r\n\t$.namespace('danny');\r\n\t$.namespace('danny2');\r\n\t$.fn.danny.foo = function() {return this.css('color', 'green')};\r\n\t$.fn.danny2.foo = function(x){alert(x); return this; };\r\n\t\/\/ now we have two different methods \"foo\"\r\n\t$('p').danny().foo(); \/\/ colors paragraphs green\r\n\t$('p').danny2().foo('Hello, world'); \/\/ alerts 'Hello, world'\r\n\t$('p').danny().foo().danny2().foo('Hello, world'); \/\/ chaining works\r\n\t$.fn.danny.add = function(a,b) { alert(a+b); return this;}; \/\/ defines a function with the same name as a real jQuery one\r\n\t$('p').danny().add(1,2).$().add('div'); \/\/ the $() plugin restores the real jQuery namespace to a chain\r\n<\/code><\/pre>\r\n      \r\n<p>The namespacing is per-chain only; <code class=\"language-javascript\">$('p').danny()<\/code> does not affect any subsequent statements. Plugins that\r\ncall <code class=\"language-javascript\">pushStack<\/code> will reset the namespacing, but in general the namespace function should be called right before the method, so that should not be an issue.<\/p>\r\n<p>This is inefficient, obviously, adding an extra function call and possible a lot of copying with <code class=\"language-javascript\">extend<\/code>, but for most code that is insignificant.<\/p>","protected":false},"excerpt":{"rendered":"jQuery encourages using namespaces for methods in the $ namespace, like $.foo.bar() rather than $.bar(). This works for $ because methods don't expect this to refer to anything specific, and the way javascript works is to assign this to the last-named object, so in $.foo.bar(), this refers to $.foo. This idea fails for plugins, however, [&hellip;]","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/28"}],"collection":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/comments?post=28"}],"version-history":[{"count":3,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/28\/revisions"}],"predecessor-version":[{"id":77,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/28\/revisions\/77"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=28"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=28"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=28"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}