Wednesday 8 November 2017

javascript - "This" within es6 class method

itemprop="text">



For some reason
I'm getting weird values for "this" in my es6
class...



data-hide="false">

class="snippet-code-js lang-js prettyprint-override">'use
strict';
class Clicker {

constructor(element)
{
this.count = 0;
this.elem = element;

this.elem.addEventListener('click', this.click);

// logs Clicker
{ count:0, elem: button#thing} as expected
console.log(this);

}

click() {

// logs id="thing">... as unexpected...

console.log(this);
this.count++;

}
}


var thing =
document.getElementById('thing');
var instance = new
Clicker(thing);







Question:



Why
is the "this" inside of of the Clickers' click method referring to the dom node rather
than ... itself?



More importantly, how do I
refer to Clickers' count property from within its' click method if I can't use "this" to
do it?



Answer






Why
is the "this" inside of of the Clickers' click method referring to
the dom
node rather than ...
itself?




Because
the specification for .addEventListener() is to set the
this pointer to the DOM element that caught the event. That's
how it is designed to work.



/>

When passing a method as a callback where you want
to override the value of this, you can use
.bind() to force the desired value of
this with
it:




this.elem.addEventListener('click',
this.click.bind(this));


Explanation:



All
function calls in Javascript set a new value of this according
to how the function is called. See href="https://stackoverflow.com/questions/28016664/when-you-pass-this-as-an-argument/28016676#28016676">this
explanation for further info on that basic set of
rules.



On top of that, when you do
this:




this.elem.addEventListener('click',
this.click);


You are
just getting the this.click method and passing that method
alone to addEventListener(). The value of
this will be completely lost. It's as if you are doing
this:



var m = this.click; // m
here is just a reference to
Clicker.prototype.click
this.elem.addEventListener('click',
m);


On top of this,
.addEventListener() is specifically built to set it's own value
of this when it calls the callback (to point
this at the element creating the
event).




So, you can use
.bind() as shown above to force the proper value of
this to be in place when your method is
called.






For
reference, you may find href="https://stackoverflow.com/questions/28016664/when-you-pass-this-as-an-argument/28016676#28016676">this
description of the six ways that this is set for a
function call in Javascript to be useful.



/>

Other
Options




I find
.bind() to be the clearest way of defining this, but you could
also use either a local anonymous
function:



var self =
this;
this.elem.addEventListener('click', function() {

self.click();
});


or
in ES6, an arrow
function:




this.elem.addEventListener('click',
() =>
this.click());


The
arrow function will preserve the value of this for you
automatically to avoid needing the self reference used in the
prior example.


No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print &q...