Javascript this, that, and arrow functions

Hey, guys! So, recently I stumbled upon a problem that people might easily notice and meet every day during their software development. In Object Oriented Programming, we all know that there is a this object that refers to its parent object. It is available in a lot of languages, including Javascript. This article wraps up nicely on how this object behaves in a browser window. If you haven’t read it, I highly recommend you to do so! (no sell-out)


From the article, we know that if we create a global function, the this object will refer to the browser window. This happens because the browser window is the top-level parent in our view. What happens when we have a HTML Element that has onclick event? The this object inside the event callback function will refer to its parent, the HTML Element.

The article illustrates everything nicely in one picture

Is that all? Not really. Sometimes, when we create an object consists of attributes and functions, and this is where we might be caught off guard. Consider this code:

// test.js, running on NodeJS 6.10.0
const obj = {
  testMethod() {
    function printThis() {
      console.log(this);
    };

    printThis();
  },
};

obj.testMethod();

If I run the file above, this object will refer to NodeJS environment.

{ global: [Circular],
  process: 
  process {
  title: 'node',
  version: 'v6.10.0',
  moduleLoadList:
...

It happens because we didn’t bind the printThis function to obj, causing it to refer to its parent instead, the NodeJS environment. There is an old-school way to play around this:

// test.js, running on NodeJS 6.10.0
const obj = {
  testMethod() {
    // assign this to a variable
    const that = this;

    function printThis() {
      // prints the 'obj' object
      // because the variable that refers to obj
      console.log(that);
    };

    printThis();
  },
};

obj.testMethod();

Hey, I’m not a fan of assigning this to a variable. What should I do? I’m sad to say it, but it is probably one of the most versatile solution to handle the scoping of this object. The other way is to bind the function to the valid this object.

// test.js, running on NodeJS 6.10.0 
const obj = { 
  testMethod() { 
    function printThis() {
      console.log(this); 
    }
    
    // bind printThis to this object
    const printThat = printThis.bind(this);
    printThat(); // prints obj
  }, 
}; 

obj.testMethod();

The obj could be printed out because we have bound the printThis function and this object to a brand new function, printThat. This way, the this object accessed inside the printThat function will refer to obj. If these things might still seem ugly to you, you might want to know a little thing that does everything, the arrow function.

// test.js, running on NodeJS 6.10.0
const obj = {
  testMethod() {
    const printThis = () => {
      // prints obj
      console.log(this);
    };

    printThis();
  },
};

obj.testMethod();

Wait, what? How? Say hello to arrow functions. It is an ES6 syntax that allows you to create a shorter syntax of a return expression AND bind the function to its parent. So, in this case, we bound the printThis to obj and therefore, obj was printed instead of NodeJS environment.

Did you say about shorter syntax of return expression? How does it work? Well, it is as simple as this:

// test.js, running on NodeJS 6.10.0
this.x = 16;

const obj = {
  x: 8,
  testMethod() { return this.x; },
  testMethod2: () => this.x
};

console.log(obj.testMethod()); // prints 8
console.log(obj.testMethod2()); // prints 16

THIS IS SORCERY! Yeah, but it is real. Arrow functions have been around for a quite while. This thing also helps people when they are developing a React Component that has onClick event, such as:

class SelectFilter extends React.Component {
  constructor() {
    super();
    
    // Override onInputChange to a bound function
    this.onInputChange = this.onInputChange.bind(this);
  }

  onInputChange(e) {
    e.preventDefault();

    this.props.onChangeFilter(e.target.value);
  }

  render() {
    return (
      <FormGroup controlId={`select-filter-${this.props.keyName}`}>
        <InputGroup>
          <FormControl
            type="text"
            value={this.props.filterText}
            placeholder="Enter text"
            onChange={this.onInputChange()}
          />
        </InputGroup>
      </FormGroup>
    );
  }
}

In the code snippet above, I overrode the onInputChange handler inside the constructor with a function that binds onInputChange to SelectFilter. The other way is to bind the handler inside the render function like this.

class SelectFilter extends React.Component {
  onInputChange(e) {
    e.preventDefault();

    this.props.onChangeFilter(e.target.value);
  }

  render() {
    return (
      <FormGroup controlId={`select-filter-${this.props.keyName}`}>
        <InputGroup>
          <FormControl
            type="text"
            value={this.props.filterText}
            placeholder="Enter text"
            onChange={(e) => this.onInputChange(e)}
          />
        </InputGroup>
      </FormGroup>
    );
  }
}

But, according to this article, using arrow functions in JSX is not a good pattern, and also, I feel it is really awkward to bind every handlers you have with this way. What happens if you have a lot of handlers? Your code will be pretty much filled with repetitive temporary function creations every time you render that component. This is my favorite way to bind handlers in a React Component– binding it during its definition.

class SelectFilter extends React.Component {
  onInputChange = (e) => {
    e.preventDefault();

    this.props.onChangeFilter(e.target.value);
  }

  render() {
    return (
      <FormGroup controlId={`select-filter-${this.props.keyName}`}>
        <InputGroup>
          <FormControl
            type="text"
            value={this.props.filterText}
            placeholder="Enter text"
            onChange={this.onInputChange()}
          />
        </InputGroup>
      </FormGroup>
    );
  }
}

As I have written before, if I don’t use arrow function on onInputChange handler, this object will refer to the HTML Element instead of the SelectFilter component– and take note: HTML Element is not React Component. That is why I could access the props inside the onInputChange handler. This is really useful in React because you don’t need to bind every function that needs to utilize props or state in the constructor or in the render function.


That being said, I believe there will be a lot of surprises by ECMAScript in the future. Check out the ES7 development and have your mind not being blown by its alien syntaxes. On a side note, I will try using Medium for future software development posts (and will re-post this post, too, probably) just to compare the ease of access and the traffic. Until next time, guys!

Advertisements

Leave a Reply - No foul language and spam please :)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s