
{"id":2297,"date":"2017-01-11T00:36:50","date_gmt":"2017-01-11T05:36:50","guid":{"rendered":"http:\/\/www.ikriv.com\/blog\/?p=2297"},"modified":"2017-01-14T19:01:05","modified_gmt":"2017-01-15T00:01:05","slug":"javascript-wtf-2-the-this-keyword-part-2","status":"publish","type":"post","link":"https:\/\/ikriv.com\/blog\/?p=2297","title":{"rendered":"JavaScript WTF #2: the this keyword (part 2)"},"content":{"rendered":"<p>&#8230;Continued from <a href=\"http:\/\/www.ikriv.com\/blog\/?p=2250\">Part 1<\/a>.<\/p>\n<h4>Arrow functions<\/h4>\n<p>ES6 introduces <i>arrow functions<\/i>, which can take several forms:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n()=&gt;expression\r\nx=&gt;expression\r\n(x,y)=&gt;expression\r\n()=&gt;{operators}\r\nx=&gt;{operators}\r\n(x,y)=&gt;{operators}\r\n<\/pre>\n<p>Besides being a shorter notation for <code>function()<\/code>, arrow functions have special rule for <code>this<\/code>. They inherit <code>this<\/code> from their immediate lexical context. This makes arrow functions ideal for callbacks. Consider the following code:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n'use strict'\r\n\r\nvar obj = {\r\n    value: 42,\r\n    delayInc() { \r\n         setTimeout(function() { \r\n             console.log(&quot;Incremented value: &quot; + ++this.value); \/\/ oops...\r\n             console.log(this);\r\n\t }, 10);\r\n    },\r\n}\r\nobj.delayInc();\r\n<\/pre>\n<p>This prints<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nIncremented value: NaN\r\nTimeout {\r\n  _called: true,\r\n  _idleTimeout: 10,\r\n  _idlePrev: null,\r\n  _idleNext: null,\r\n  _idleStart: 96,\r\n  _onTimeout: &#x5B;Function],\r\n  _timerArgs: undefined,\r\n  _repeat: null,\r\n  value: NaN }\r\n<\/pre>\n<p>Why <code>NaN<\/code>? The hint is in the subsequent lines: <code>this<\/code> value of the callback is (somewhat arbitrarily) set to a <code>Timeout<\/code> object. In other languages, the <code>Timeout<\/code> object would probably have been passed as a parameter, but in JavaScript we have <code>this<\/code>, which can be set to anything, so why not use it? Consequently, <code>this.x<\/code> in the callback refers to <code>Timeout.x<\/code>, which is <code>undefined<\/code>, and not to <code>obj.x<\/code> as one might have expected. Incrementing <code>undefined<\/code> yields <code>NaN<\/code>, and <code>obj.x<\/code> remains unchanged.<\/p>\n<p>Pre-EcmaScript 6 fix to this problem was to introduce an extra variable:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n'use strict'\r\n\r\nvar obj = {\r\n    value: 42,\r\n    delayInc() { \r\n         var $this = this;\r\n         setTimeout(function() { \r\n             console.log(&quot;Incremented value: &quot; + ++$this.value); \r\n             console.log($this);\r\n\t }, 10);\r\n    },\r\n}\r\n\r\nobj.delayInc();\r\n<\/pre>\n<p>This works as expected:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nIncremented value: 43\r\n{ value: 43, delayInc: &#x5B;Function: delayInc] }\r\n<\/pre>\n<p>With arrow functions we can get rid of the extra variable and shorten the code:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n'use strict'\r\n\r\nvar obj = {\r\n    value: 42,\r\n    delayInc() { \r\n         setTimeout(() =&gt; { \r\n             console.log(this);\r\n             console.log(++this.value); \r\n\t }, 10);\r\n    },\r\n}\r\n\r\nobj.delayInc();\r\n<\/pre>\n<p>This snippet behaves exactly like previous one, printing<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nIncremented value: 43\r\n{ value: 43, delayInc: &#x5B;Function: delayInc] }\r\n<\/pre>\n<p>Unfortunately, inheriting <code>this<\/code> from the lexical context makes arrow functions unsuitable in some other contexts. Consider:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n'use strict'\r\n\r\nvar obj = {\r\n    value: 42,\r\n    inc: ()=&gt;++this.value,\r\n    inc2() { return ++this.value; }\r\n}\r\n\r\nconsole.log(obj.inc(), obj.inc2());\r\n<\/pre>\n<p>This prints<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nNaN 43\r\n<\/pre>\n<p>The arrow function <code>inc()<\/code> takes <code>this<\/code> from the surrounding context, setting it to the global object. Similarly looking regular member function <code>inc2()<\/code> has its <code>this<\/code> set to <code>obj<\/code> at the time of invocation.<\/p>\n<p>Unlike Java and C#, where lambdas are nearly equivalent to regular methods, in JavaScript they behave quite differently.<\/p>\n<h4>This in static context<\/h4>\n<p>In most languages &#8220;static&#8221; methods don&#8217;t have this. JavaScript is, again, different:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nclass Foo {\r\n    static f() { \r\n\tconsole.log(this, this === Foo);\r\n    }\r\n}\r\n\r\nFoo.f();\r\n<\/pre>\n<p>This prints<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n&#x5B;Function: Foo] true\r\n<\/pre>\n<p>In static contexts <code>this<\/code> points to the surrounding class, which is actually a function.<\/p>\n<h4>Conclusion<\/h4>\n<p>Simply put, there are two many rules governing the value of <code>this<\/code> in JavaScript. If I write a simple function printing <code>this<\/code>, it can print virtually anything, depending on how we invoke it, and it is by design.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nfunction f() { console.log(this); }\r\n\r\nf();                      \/\/ 'global object' or undefined in strict mode\r\nvar obj = { f }; obj.f(); \/\/ obj\r\nnew f();                  \/\/ newly created object of type f\r\nf.call({x:42});           \/\/ { x: 42 }\r\nf.bind({x:42})();         \/\/ { x: 42 }\r\n<\/pre>\n<p>ES6 arrow and static functions add even more rules and special cases.<\/p>\n<p>Such versatility makes JavaScript <code>this<\/code> a really powerful mechanism. Think through how many hoops you would have to jump to call method of one C# class on an instance of another C# class. On the other hand, why would you want to do it? Even if C# had such a feature, it probably would have been considered extremely dangerous and not suitable for use under normal circumstances. Anyway, huge power and flexibility of JavaScript <code>this<\/code> comes at the expense of simplicity and safety: it provides a number of excellent devices to shoot oneself in the foot.<\/p>\n<p><a style=\"display: none;\" href=\"https:\/\/www.codeproject.com\" rel=\"tag\">CodeProject<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8230;Continued from Part 1. Arrow functions ES6 introduces arrow functions, which can take several forms: ()=&gt;expression x=&gt;expression (x,y)=&gt;expression ()=&gt;{operators} x=&gt;{operators} (x,y)=&gt;{operators} Besides being a shorter notation for function(), arrow functions <a href=\"https:\/\/ikriv.com\/blog\/?p=2297\" 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-2297","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\/2297","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=2297"}],"version-history":[{"count":18,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2297\/revisions"}],"predecessor-version":[{"id":2315,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/2297\/revisions\/2315"}],"wp:attachment":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2297"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2297"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2297"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}