{"id":21,"date":"2012-12-07T17:00:48","date_gmt":"2012-12-07T23:00:48","guid":{"rendered":"http:\/\/laubsterboy.com\/blog\/?p=21"},"modified":"2012-12-07T17:00:48","modified_gmt":"2012-12-07T23:00:48","slug":"javascript-implicit-and-explicit-context","status":"publish","type":"post","link":"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/","title":{"rendered":"JavaScript Implicit and Explicit Context"},"content":{"rendered":"<p>Several years ago I was having a conversation with a friend about the future of the web and if it involved Abobe Flash or if it would eventually be replaced by HTML5 \/ JavaScript \/ CSS. The argument between the two went many different directions, however by the end of the conversation it was obvious that regardless of which remained dominant I really needed to learn more about HTML5, JavaScript, and CSS.<\/p>\n<p>Coming from a background in Flash (ActionScript)\u00a0the part that intrigued me most was JavaScript, specifically using it as a OOP language. I read several books, scoured the web for articles and tutorials, and quickly felt that I had a decent handle on how it was commonly used. As I continued to experiment with increasingly complex interface designs and coding techniques I ran into the same problem time and time again. The context of the keyword <strong>this<\/strong> was very inconsistent and at times not at all what I expected it to be. If you&#8217;ve ever used <strong>this<\/strong> in conjunction with an event listener or timeout callback function\u00a0to reference a dynamically created variable or an object property then it&#8217;s quite likely that you too have had the pleasure of seeing how JavaScript handles implicit references. Let&#8217;s take a look at some code to see exactly what is going on.<\/p>\n<p>In the below\u00a0example we&#8217;ll create a simple list of collapsible\u00a0paragraphs.<\/p>\n<pre class=\"theme:twilight lang:js decode:true\">&lt;!DOCTYPE html&gt;\n&lt;html lang=\"en\" xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"&gt;\n&lt;head&gt;\n    &lt;meta charset=\"utf-8\" \/&gt;\n    &lt;title&gt;laubsterboy.com Example&lt;\/title&gt;\n    &lt;style type=\"text\/css\"&gt;\n        .collapsibleContent {display:none;}\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;a href=\"#\" class=\"collapsibleTitle\"&gt;Title 1&lt;\/a&gt;\n    &lt;p class=\"collapsibleContent\"&gt;The first short paragraph example.&lt;\/p&gt;\n    &lt;a href=\"#\" class=\"collapsibleTitle\"&gt;Title 2&lt;\/a&gt;\n    &lt;p class=\"collapsibleContent\"&gt;The second short paragraph example.&lt;\/p&gt;\n    &lt;a href=\"#\" class=\"collapsibleTitle\"&gt;Title 3&lt;\/a&gt;\n    &lt;p class=\"collapsibleContent\"&gt;The third short paragraph example.&lt;\/p&gt;\n\n    &lt;script type=\"text\/javascript\"&gt;\n        (function (window) {\n            function Collapsible(title, content) {\n                this.title = title;\n                this.content = content;\n                this.collapsed = true;\n                \/\/\n                this.title.addEventListener(\"click\", this.titleClickListener, false);\n            }\n            Collapsible.prototype.titleClickListener = function (Event) {\n                if (this.collapsed) {\n                    this.expand();\n                } else {\n                    this.collapse();\n                }\n            }\n            Collapsible.prototype.expand = function() {\n                this.collapsed = false;\n                this.content.style.display = \"block\";\n            }\n            Collapsible.prototype.collapse = function() {\n                this.collapsed = true;\n                this.content.style.display = \"none\";\n            }\n\n            var init = (function () {\n                var anchors = document.body.getElementsByTagName(\"a\");\n                var paragraphs = document.body.getElementsByTagName(\"p\");\n                \/\/\n                var titles = new Array();\n                var contents = new Array();\n                \/\/\n                for (var i = 0; i &lt; anchors.length; i++) {\n                    if (anchors[i].className == \"collapsibleTitle\") {\n                        titles.push(anchors[i]);\n                    }\n                }\n                for (var i = 0; i &lt; paragraphs.length; i++) {\n                    if (paragraphs[i].className == \"collapsibleContent\") {\n                        contents.push(paragraphs[i]);\n                    }\n                }\n                for (var i = 0; i &lt; titles.length; i++) {\n                    var tempCollapsible = new Collapsible(titles[i], contents[i]);\n                }\n            })();\n        })(window);\n    &lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n<p>In the above example we&#8217;ve created the <strong>Collapsible<\/strong> class which contains references to the pairs of titles and content containers, and added a click event listener to each of the titles. The problem with the above example right now is that the keyword <strong>this<\/strong> within the scope of the <strong>titleClickListener<\/strong> function refers to the <strong>collapsibleTitle<\/strong>\u00a0anchor element\u00a0rather than the instance of the <strong>Collapsible<\/strong> object. The click event listener is working properly, except that the listener is only operating within the scope of the <strong>collapsibleTitle<\/strong> anchor element and thus it doesn&#8217;t have access to any of the <strong>Collapsible<\/strong> object properties or\u00a0prototype functions.<\/p>\n<p>One way to resolve this problem is to bring the click event listener function into the scope of the <strong>Collapsible<\/strong> class constructor and provide it with a reference to the scope of the <strong>Collapsible<\/strong> class.<\/p>\n<pre class=\"theme:twilight start-line:20 lang:default decode:true\">function Collapsible(title, content) {\n    this.title = title;\n    this.content = content;\n    this.collapsed = true;\n    var self = this; \/\/ create a variable that contains a reference to the keyword this\n    this.title.addEventListener(\"click\", function (Event) {\n        if (self.collapsed) {\n            self.expand();\n        } else {\n            self.collapse();\n        }\n    }, false);\n}<\/pre>\n<p>Problem solved! Now when you click on any of the titles the corresponding content will collapse or expand. However, there are a few things left to be desired with this approach. First, the code is much more difficult to read and understand,\u00a0mostly due to\u00a0the <strong>self<\/strong> keywords and functions nested\u00a0within functions. Second, the <strong>titleClickListener<\/strong> function is no longer a prototype of the <strong>Collapsible<\/strong> class but rather a property, so it is no longer shared by each <strong>Collapsible<\/strong> instance object which uses more memory and in larger projects would slow performance. Lastly, since the function is declared locally within the scope of the <strong>addEventListener<\/strong> call there is no way for it to be shared with other events if it were ever necessary.<\/p>\n<p>Since the root problem is that the context of the keyword <strong>this<\/strong> is being implicitly set by JavaScript and changing within the scope of the <strong>titleClickListener,<\/strong> a better approach would be to explicitly set the context of the keyword <strong>this<\/strong> when calling <strong>titleClickListener<\/strong>. This would mean that the keyword <strong>this<\/strong> could reference the <strong>Collapsible<\/strong> instance object rather than the <strong>collapsibleTitle<\/strong> anchor element. Thankfully there are two methods for doing this within JavaScript, <strong>Call<\/strong> and <strong>Apply<\/strong>. <strong>Call<\/strong> accepts an argument list while <strong>Apply<\/strong> accepts an argument array.<\/p>\n<p>So, let&#8217;s incorporate the <strong>Call<\/strong> method into our code to see just how this works. If we revert back to the first code example and replace line 25 with the code below, everything should be working properly.<\/p>\n<pre class=\"theme:twilight start-line:25 lang:js decode:true\">this.title.addEventListener(\"click\", function() { self.titleClickListener.call(self, arguments)}, false);<\/pre>\n<p>One last adjustment that we could make is to add a delegate prototype function to the <strong>Collapsible<\/strong> class. This could be invoked each time the context of an object needs to be adjusted when calling a function.<\/p>\n<pre class=\"theme:twilight start-line:42 lang:js decode:true\">Collapsible.prototype.delegate = function (fnc, obj) { var that = obj; return function () { fnc.call(that, arguments); } }<\/pre>\n<p>Once the delegate function is added we can now make our last adjustment to the <strong>addEventListener<\/strong> call.<\/p>\n<pre class=\"theme:twilight start-line:25 lang:js decode:true\">this.title.addEventListener(\"click\", this.delegate(this.titleClickListener, this), false);<\/pre>\n<p>That&#8217;s it! The delegate call will return a function that will call <strong>this.titleClickListener<\/strong> with the context of <strong>this<\/strong>, which is referencing the <strong>Collapsible<\/strong> object.<\/p>\n<p>Learning about and understanding these two methods\u00a0have had a dramatic impact on what I&#8217;ve been capable of accomplishing with JavaScript, taking my skill to an entirely new level, and I genuinely hope that this post has helped you to learn something new or at least inspire you to do some research and studying of your own.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Several years ago I was having a conversation with a friend about the future of the web and if it involved Abobe Flash or if it would eventually be replaced by HTML5 \/ JavaScript \/ CSS. The argument between the two went many different directions, however by the end of the conversation it was obvious [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[3],"tags":[7,11,18,36,45,53],"class_list":["post-21","post","type-post","status-publish","format-standard","hentry","category-guide","tag-apply","tag-call","tag-delegate","tag-javascript","tag-oop","tag-prototype"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>JavaScript Implicit and Explicit Context - John Russell Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"JavaScript Implicit and Explicit Context - John Russell Blog\" \/>\n<meta property=\"og:description\" content=\"Several years ago I was having a conversation with a friend about the future of the web and if it involved Abobe Flash or if it would eventually be replaced by HTML5 \/ JavaScript \/ CSS. The argument between the two went many different directions, however by the end of the conversation it was obvious [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/\" \/>\n<meta property=\"og:site_name\" content=\"John Russell Blog\" \/>\n<meta property=\"article:published_time\" content=\"2012-12-07T23:00:48+00:00\" \/>\n<meta name=\"author\" content=\"John Russell\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@laubsterboy\" \/>\n<meta name=\"twitter:site\" content=\"@laubsterboy\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"John Russell\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/\"},\"author\":{\"name\":\"John Russell\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c\"},\"headline\":\"JavaScript Implicit and Explicit Context\",\"datePublished\":\"2012-12-07T23:00:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/\"},\"wordCount\":764,\"commentCount\":0,\"keywords\":[\"apply\",\"call\",\"delegate\",\"JavaScript\",\"OOP\",\"Prototype\"],\"articleSection\":[\"Guide\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/\",\"url\":\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/\",\"name\":\"JavaScript Implicit and Explicit Context - John Russell Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#website\"},\"datePublished\":\"2012-12-07T23:00:48+00:00\",\"author\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.johnrussell.dev\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"JavaScript Implicit and Explicit Context\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#website\",\"url\":\"https:\/\/www.johnrussell.dev\/blog\/\",\"name\":\"John Russell Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.johnrussell.dev\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c\",\"name\":\"John Russell\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/00ce0f258fcc5e5d29897a5e81316009713e9104cfaf49f481c5bce3f81c7cb1?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/00ce0f258fcc5e5d29897a5e81316009713e9104cfaf49f481c5bce3f81c7cb1?s=96&d=mm&r=g\",\"caption\":\"John Russell\"},\"url\":\"https:\/\/www.johnrussell.dev\/blog\/author\/laubsterboy\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"JavaScript Implicit and Explicit Context - John Russell Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/","og_locale":"en_US","og_type":"article","og_title":"JavaScript Implicit and Explicit Context - John Russell Blog","og_description":"Several years ago I was having a conversation with a friend about the future of the web and if it involved Abobe Flash or if it would eventually be replaced by HTML5 \/ JavaScript \/ CSS. The argument between the two went many different directions, however by the end of the conversation it was obvious [&hellip;]","og_url":"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/","og_site_name":"John Russell Blog","article_published_time":"2012-12-07T23:00:48+00:00","author":"John Russell","twitter_card":"summary_large_image","twitter_creator":"@laubsterboy","twitter_site":"@laubsterboy","twitter_misc":{"Written by":"John Russell","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/#article","isPartOf":{"@id":"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/"},"author":{"name":"John Russell","@id":"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c"},"headline":"JavaScript Implicit and Explicit Context","datePublished":"2012-12-07T23:00:48+00:00","mainEntityOfPage":{"@id":"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/"},"wordCount":764,"commentCount":0,"keywords":["apply","call","delegate","JavaScript","OOP","Prototype"],"articleSection":["Guide"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/","url":"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/","name":"JavaScript Implicit and Explicit Context - John Russell Blog","isPartOf":{"@id":"https:\/\/www.johnrussell.dev\/blog\/#website"},"datePublished":"2012-12-07T23:00:48+00:00","author":{"@id":"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c"},"breadcrumb":{"@id":"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.johnrussell.dev\/blog\/2012\/12\/javascript-implicit-and-explicit-context\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.johnrussell.dev\/blog\/"},{"@type":"ListItem","position":2,"name":"JavaScript Implicit and Explicit Context"}]},{"@type":"WebSite","@id":"https:\/\/www.johnrussell.dev\/blog\/#website","url":"https:\/\/www.johnrussell.dev\/blog\/","name":"John Russell Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.johnrussell.dev\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/296c0c6bd1deeeb20834393e1e16325c","name":"John Russell","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.johnrussell.dev\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/00ce0f258fcc5e5d29897a5e81316009713e9104cfaf49f481c5bce3f81c7cb1?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/00ce0f258fcc5e5d29897a5e81316009713e9104cfaf49f481c5bce3f81c7cb1?s=96&d=mm&r=g","caption":"John Russell"},"url":"https:\/\/www.johnrussell.dev\/blog\/author\/laubsterboy\/"}]}},"_links":{"self":[{"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/posts\/21","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/comments?post=21"}],"version-history":[{"count":0,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/posts\/21\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/media?parent=21"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/categories?post=21"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.johnrussell.dev\/blog\/wp-json\/wp\/v2\/tags?post=21"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}