-1

I see that several people write it, in particular when we speak about ES6 together with React. But I don't find any information about this point in any javascript documentation.

So, is it true? Can we say that, apart from React, when we use ES6 class all its methods are not automatically bound to the instances created through that class?

marco
  • 1,152
  • 1
  • 9
  • 20
  • 1
    You need to show code. You are using terms ambiguously. If I understand you correctly (and that's not a given) then the answer is that methods 'defined on a class' (whatever that means) are indeed 'bound' (whatever that means) to instances. – Jared Smith Oct 19 '17 at 14:58
  • 1
    No....where'd you hear that from? Why `apart from react`? Why would React's ES6 syntax be any different than any other ES6 syntax? – Adam Jenkins Oct 19 '17 at 14:58
  • @Adam among the comments of the right answer to this question, for example https://stackoverflow.com/questions/29577977/unable-to-access-react-instance-this-inside-event-handler – marco Oct 19 '17 at 15:01
  • 2
    @marco - wow. 4 upvotes for that comment by a user with 20k reputation (https://stackoverflow.com/questions/29577977/unable-to-access-react-instance-this-inside-event-handler#comment69890374_29578232) - please someone verify for me that this is incorrect information. It seems this user with good reputation has misunderstood that event handlers in the DOM are always called in the context of the element that fired it. – Adam Jenkins Oct 19 '17 at 15:08
  • @Adam "In ES6, methods defined on a class are not automatically bound to the instance." What part of that is wrong? The method is not being called in the context of the class is was declared with. Instead, `this` will be equal to the element which it's attached to. Unless, of course, you apply a hard binding via `bind` or an arrow function. Sorry if I'm misunderstanding you but it looks you're both saying the same thing. – Mike Cluck Oct 19 '17 at 15:15
  • 1
    @MikeC - they are **automatically** bound to the instance meaning that if you don't call, apply or bind a method, then it will execute in the context of the instance - e.g. `myInstance.myMethod()` executes in the context of `myInstance`. If you `call` or `apply` a method (like the DOM implementation does when it fires event handlers) then the context is being manipulated at call time. So yes, the methods are **automatically** bound to the instance, but that's not to say that can't be executed in another context....at least that's how I'd say it. – Adam Jenkins Oct 19 '17 at 15:19
  • Some people might argue it's semantics, but it's probably best to say that ES6 class methods are **automatically bound** to the instance, but they are not **permanently bound**. – Adam Jenkins Oct 19 '17 at 15:32
  • @Adam Well, that's specific to DOM methods. DOM methods will call a method setting `this` to be the element in question but the method itself isn't automatically bound to anything. I was literally about to say we're arguing semantics when your latest comment popped up haha. I'd still say that it's incorrect to say the class methods are automatically bound to the instance since they are **not** automatically bound to the instance of the class. They are not actually bound to anything until given a binding context (`bind`, `this.method`, defined as an arrow function, etc.) – Mike Cluck Oct 19 '17 at 15:33
  • 1
    @Adam: I wouldn’t use that term in that case. All you have is a “normal” method call. There is nothing special about class methods. They work like function properties of any other object. Automatically bound usually means that this works: `var bar = foo.bar; bar();` (function is bound to `foo`). Python works like this. – Felix Kling Oct 19 '17 at 15:35
  • @FelixKling - but there is something special about class methods - they are part of the prototype (remember pre-ES6?). They're not just like a function property hanging off an object literal. By running the code in your comment, you are, arguably, manually manipulating the context of the method. – Adam Jenkins Oct 19 '17 at 15:37
  • 1
    @Adam: That makes no difference for calling the method (i.e. it doesn't matter where the property is defined in the prototype chain). A "bound" function refers to a very specific type of function. It's a function object with a fixed value for `this` that cannot be changed no matter how the function is executed. Merely setting the `this` value during execution to a specific value (what `foo.bar()`) does, is not considered "binding". Otherwise every function would be "bound" since a value for `this` is set whenever the function is executed. – Felix Kling Oct 19 '17 at 15:41
  • @Adam: Let me clarify what I meant with *"There is nothing special about class methods."*: The fact that `foo.bar()` sets the `this` value of `bar` to `foo` has nothing to do with class methods. This is how JavaScript has always worked. – Felix Kling Oct 19 '17 at 15:58
  • @FelixKling - of course that's the way JS always worked, I never said that ES6 had anything "special" going on with it compared to any other version of JS. The author implied that there was a difference. – Adam Jenkins Oct 19 '17 at 16:55

1 Answers1

1

[W]hen we use ES6 class all its methods are not automatically bound to the instances created through that class?

They're not strictly bound, no. That means you can still use them without an instance of that class. This is true for all of ES2015+.

class A {
  log() {
    console.log(this.value);
  }
}

let a = new A();
let b = { value: 'B' };
a.log.call(b);

...apart from React...

Nothing about React changes how methods are bound. What people mean when they talk about that is that the methods aren't lexically bound this will not give you what you expect:

class MyComponent extends React.Component {
  constructor() {
    super();
    this.value = 'MyComponent';
  }

  showValue() {
    console.log(this.value);
  }

  render() {
    return (
      <button onClick={this.showValue}>Click Me</button>
    );
  }
}

Because showValue has not been bound to the instance of MyComponent, it will value to retrieve the this.value property.

To make this work correctly you can do the following with existing syntax:

class MyComponent extends React.Component {
  constructor() {
    super();
    this.value = 'MyComponent';
    this.showValue = this.showValue.bind(this);
  }

  showValue() {
    console.log(this.value);
  }

  render() {
    return (
      <button onClick={this.showValue}>Click Me</button>
    );
  }
}

or with field declarations (this is, as of Oct. 19 2017, currently proposed and is not a part of the core language):

class MyComponent extends React.Component {
  constructor() {
    super();
    this.value = 'MyComponent';
  }

  showValue = () => {
    console.log(this.value);
  }

  render() {
    return (
      <button onClick={this.showValue}>Click Me</button>
    );
  }
}
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
  • `all its methods are not automatically bound to the instances created through that class` - the answer to this question is no, it is not true – Adam Jenkins Oct 19 '17 at 15:02
  • This example in react has nothing to do with ES6 per se. If you add an event listener to any element (ES-whatever, in vanilla JS or any other framework) the context the bound listener is fired in will automatically be set to the element - that is part of the DOM API, it has nothing to do with ES6, react, or anything else. – Adam Jenkins Oct 19 '17 at 15:04
  • @Adam Right, it's not a React specific thing. I apologize if it comes across that way. The question was asked in the context of binding React methods so that's the question I answered directly. – Mike Cluck Oct 19 '17 at 15:05
  • @MikeC - when somebody looks at the **title** of the OPs question and sees this answer, then it will be confusing. – Adam Jenkins Oct 19 '17 at 15:06
  • @Adam I've edited the answer to hopefully be more clear to future people – Mike Cluck Oct 19 '17 at 15:10
  • Sorry but **why** `showValue` has not been bound to the instance of MyComponent? Maybe we refer to a different thing when we speak about `an instance of MyComponent`? For me in this case MyComponent is a class and the instance is (roughly speaking) an object created through that class. So, in this case I imagine that under the hood React library creates an object with that class in this way, `new MyComponent`. In a "normal" situation, creating an object with `new ClassName`, all the methods would be automatically bound to the instance. In React it doesn't happen. I would say, just in React... – marco Oct 19 '17 at 15:36
  • 2
    @marco It isn't strictly bound to an instance of MyComponent because that's how functions work in JavaScript. It's the same as if you did `var obj = { f() { ... } }`. `f` is not bound to `obj`. You can do `let f = obj.f; f()` and `this` inside of `f` will not be equal to `obj`. I suggest reading [this question](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) for more information on how `this` works in relation to functions. – Mike Cluck Oct 19 '17 at 15:38
  • 1
    @marco Also, you're misunderstanding *how* the method is called. When you do `myComponent.showValue()` where `myComponent` is an instance of `MyComponent`, you're setting the `this` value inside of `showValue` to `myComponent` because of the way you called it. When DOM methods are called, it's more like `let showValue = myComponent.showValue; showValue.call(element, event)`. In that case, you are not calling `showValue` in a way which would set `this` equal to `myComponent`. – Mike Cluck Oct 19 '17 at 15:44
  • 2
    @marco: The way JavaScript is currently designed, if class methods were autobind it would mean that every instance has its own copy of the method (because every instance is a distinct object). I.e. if I have two instances and would compare their methods with `instance1.foo === instance2.foo` I would get `false`. That's not what happens though, therefore class methods are not autobound (and of course you could read the spec if you want to). – Felix Kling Oct 19 '17 at 15:56