3

Still new to ES6 so trying to understand why there's a difference between these two functions below. I'm working in React and am noticing that I'm getting an error when writing a non-ES6 function that sets state. This is happening within componentDidMount.

This way in ES6 works and returns what i need:

(pos) => this.setState({
    lat: pos.coords.latitude,
    lng: pos.coords.longitude,
  })

However, to this way throws an error - "Uncaught TypeError: this.setState is not a function"

 function(pos) {
    this.setState({
      lat: pos.coords.latitude,
      lng: pos.coords.longitude
    })
  }

Aren't these the exact same thing? Can anyone explain why it would be throwing this error?

Here is the code from the react class to provide more context:

var GeolocationExample = React.createClass({
  getInitialState: function() {
    return {
      lat: '',
      lng: '',
    };
  },

  componentDidMount: function() {
    navigator.geolocation.getCurrentPosition(

      // Where I'm placing each of the above mentioned functions,

      (err) => alert(err.message),
    );
  },

  render: function() {
    return (
      <View>
        <Text>
          <Text style={styles.title}>Initial position: </Text>
          {this.state.lat}
        </Text>
        <Text>
          <Text style={styles.title}>Current position: </Text>
          {this.state.lng}
        </Text>
      </View>
    );
  }
});

Any and all help is appreciated. Thank you!

dace
  • 5,819
  • 13
  • 44
  • 74
  • 1
    as @Andrey pointed out: `Arrow functions have implicit this binding` so the non-arrow with `(function(pos){...}).bind(this)` should be equivalent to the arrow one – birdspider Sep 04 '15 at 13:48

2 Answers2

7

No they are not the same. Arrow functions are automatically bound to the context where they are created. That means that

(x) => this.stuff = x

is (mostly) equivalent to:

(function(x) {
    return this.stuff = x;
}.bind(this))

Arrow functions will also preserve the arguments, super and new.target of the function inside which it is created.

Which means

(function a() {
  const u = () => console.log(arguments);
  u("whatever");
})("a args");

will print something like ["a args"].

See here for more information.

Quentin Roy
  • 7,677
  • 2
  • 32
  • 50
  • Thank you for that clear explanation - greatly appreciated! – dace Sep 04 '15 at 13:51
  • There's more to it that this, but this is a good intro. `arguments`, `super`, and `new.target` work in arrow functions. Arrow functions can also be created when there IS no `this` initialized yet, like in a class constructor before `super()` has been called. – loganfsmyth Sep 04 '15 at 16:41
  • Oh this is right. More exactly, just as with `this`, they preserve these values from the function where they are created. I actually did not know this. Thank you. – Quentin Roy Apr 08 '16 at 03:42
0

Lexical this

Until arrow functions, every new function defined its own this value (a new object in case of a constructor, undefined in strict mode function calls, the context object if the function is called as an "object method", etc.). This proved to be annoying with an object-oriented style of programming.

From : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

This is why, when you write:

 this.setState = function() {};
 function(pos) {
    this.setState({
      lat: pos.coords.latitude,
      lng: pos.coords.longitude
    })
  }

The this in this.setState inside the function is set to {} (an empty object).

When you write it with the => notation instead, the this is shared with the outside of the function, which is equivalent to :

 this.setState = function() {};
 var self = this;
 function(pos) {
    self.setState({
      lat: pos.coords.latitude,
      lng: pos.coords.longitude
    })
  }

or you could also use function(pos){ /* Stuff here */ }.bind(this);

edi9999
  • 19,701
  • 13
  • 88
  • 127