
{"id":2250,"date":"2017-01-06T01:08:37","date_gmt":"2017-01-06T06:08:37","guid":{"rendered":"http:\/\/www.ikriv.com\/blog\/?p=2250"},"modified":"2017-01-10T23:06:32","modified_gmt":"2017-01-11T04:06:32","slug":"javascript-wtf-2-the-this-keyword-part-1","status":"publish","type":"post","link":"https:\/\/ikriv.com\/blog\/?p=2250","title":{"rendered":"JavaScript WTF #2: the this keyword (part 1)"},"content":{"rendered":"<p>Java language specification <a href=\"https:\/\/docs.oracle.com\/javase\/specs\/jls\/se7\/html\/jls-15.html#jls-15.8.3\">defines &#8220;this&#8221; keyword in one sentence<\/a>. EcmaScript 6 <a href=\"http:\/\/www.ecma-international.org\/ecma-262\/6.0\/#sec-this-keyword\">definition<\/a> of &#8220;this&#8221; is about a page of pseudo-code spread over several paragraphs, and there is a good reason for that. <\/p>\n<p>JavaScript&#8217;s <code>this<\/code> is defined by chain of nested &#8220;execution contexts&#8221;. It may depend on both the execution path and the static location of the caller in code, and can refer to virtually anything, or nothing at all. This makes <code>this<\/code> arguably the most confusing concept in the language. The list of gotchas related to &#8220;this&#8221; is long and quite impressive: so long in fact, that I had to divide this WTF into parts.<\/p>\n<h4>Undefined &#8220;this&#8221; for indirect method calls<\/h4>\n<p>In JavaScript <code>this<\/code> is set to <code>undefined<\/code> inside free function calls (in strict mode), and to the method-holding object inside method calls. It makes perfect sense, but the caveat is that if we call an <i>expression<\/i> whose value is a function, <code>this<\/code> will always be <code>undefined<\/code>, even if said function is actually a method of some object. Consider the following code:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n'use strict'\r\nvar obj = { \r\n    x:42, \r\n    printX() { console.log(this.x); } \/\/ method\r\n};\r\n\r\nfunction invoke(action) { action(); \/* free call *\/ }\r\n\r\nobj.printX();                 \/\/ 42\r\ninvoke(obj.printX);           \/\/ Cannot read property 'x' of undefined\r\n<\/pre>\n<p>The call on line 9 is a method call, it works as expected. The call on line 10 passes the result of the expression <code>obj.printX<\/code> as a parameter to the <code>invoke()<\/code> function. In this case <code>obj<\/code> is only used to retrieve the pointer to the <code>printX<\/code> function, and then discarded. When <code>printX<\/code> is called on line 7 via the <code>action<\/code> variable, it is considered a free function call, not a method call. Therefore, its &#8220;this&#8221; pointer is set to <code>undefined<\/code>, hence the error. <\/p>\n<p>This &#8220;feature&#8221; caused so much pain, that EcmaScript 6 defined a special work-around for it in the form of arrow functions, to be discussed in part 2.<\/p>\n<p>In certain cases, it may be tricky to distinguish when the call is a method call and when it is not:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n'use strict';\r\nobj.printX();            \/\/ 42 - method call\r\n(obj.printX)();          \/\/ 42 - method call\r\n(false || obj).printX(); \/\/ 42 - still method call\r\n(false || obj.printX)(); \/\/ Cannot read property 'x' of undefined - free call\r\n<\/pre>\n<h4>Dangerous behavior in default mode<\/h4>\n<p>If you forget to add <code>'use strict'<\/code> in the beginning of your script, it will run in default, non-strict mode. In default mode, &#8220;this&#8221; is set to &#8220;global object&#8221; for free function calls. In web browsers, global object is <code>window<\/code>. If your code happens to modify a property whose name coincides with one of the <code>window<\/code> object&#8217;s properties, it can lead to rather spectacular results:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nvar obj = { \r\n    location: &quot;right: 20px&quot;,\r\n    setLocation(side, pixels) {\r\n        this.location = side + &quot; &quot; + pixels + &quot;px&quot;;\r\n    }\r\n}\r\n\r\nfunction goLeft(setter) {\r\n    setter(&quot;left&quot;, 10);\r\n}\r\n\r\ngoLeft(obj.setLocation); \/\/ oops...\r\n<\/pre>\n<p>When run in a browser (<a href=\"http:\/\/www.ikriv.com\/dev\/js\/wtf\/location\">try it!<\/a>), this code navigates to URL &#8220;Left%2010px&#8221;, because line 4 modifies <code>window.location<\/code> instead of <code>obj.location<\/code>. It is highly unlikely this was the intended behavior.<\/p>\n<h4>The exotic kludge of bind()<\/h4>\n<p>To get around the problem of undefined &#8220;this&#8221; for function expressions, JavaScript has a special function <code>bind()<\/code> that returns an &#8220;exotic function object&#8221; (it&#8217;s an actual term from the specification). When invoked, this object sets <code>this<\/code> to the value specified. <\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n'use strict'\r\nvar obj = { \r\n    x:42, \r\n    printX() { console.log(this.x); } \r\n};\r\n\r\nfunction invoke(action) { action(); }\r\ninvoke(obj.printX.bind(obj)); \/\/ 42\r\n<\/pre>\n<p>The trouble is, with &#8220;bind&#8221; you can set <code>this<\/code> to any value, sometimes with unexpected results:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n'use strict'\r\n\r\nvar logger = {\r\n    messages: &#x5B;],\r\n    log(text) {  this.messages.push(text); },\r\n    out(level, text) { this.log(level.toUpperCase() + &quot;: &quot; + text); },\r\n    clear() { console.log(&quot;Messages logged: &quot; + this.messages.length); this.messages = &#x5B;]; }\r\n};\r\n\r\nfunction doStuff(out) {\r\n    out(&quot;debug&quot;, &quot;this is a test&quot;);\r\n}\r\n\r\ndoStuff(logger.out.bind(logger));  \/\/ Logs to logger.messages\r\nlogger.clear();                    \/\/ Messages logged: 1\r\n\r\ndoStuff(logger.out.bind(console)); \/\/ Logs to console, bypasses logger.messages\r\nlogger.clear();                    \/\/ Messages logged: 0\r\n\r\ndoStuff(logger.out.bind(Math)); \/\/ Logs nowhere; attempts to calculate logarithm of some text\r\nlogger.clear();                 \/\/ Messages logged: 0\r\n<\/pre>\n<p>To be continued&#8230;<br \/>\n<a href=\"https:\/\/www.codeproject.com\" rel=\"tag\" style=\"display:none\">CodeProject<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Java language specification defines &#8220;this&#8221; keyword in one sentence. EcmaScript 6 definition of &#8220;this&#8221; is about a page of pseudo-code spread over several paragraphs, and there is a good reason <a href=\"https:\/\/ikriv.com\/blog\/?p=2250\" class=\"more-link\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"Layout":"","footnotes":""},"categories":[4,15],"tags":[],"class_list":["entry","author-ikriv","post-2250","post","type-post","status-publish","format-standard","category-hack","category-webdev"],"_links":{"self":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2250","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2250"}],"version-history":[{"count":39,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2250\/revisions"}],"predecessor-version":[{"id":2296,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2250\/revisions\/2296"}],"wp:attachment":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2250"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2250"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2250"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}