Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Classes and arrow functions and THIS [closed]

While learning JS and React I've come across confusing differences in tutorials.

I'll split the questions below with examples. I understand bind for regular functions and this context, it's just arrow functions and how I've seen them used/declared that's confusing.

Please don't just refer to duplicates as I've found conflicting answers in tutorials which have confused me, so looking for the source of truth to understand in a simple way. Answers related to the questions and examples below would help better.

1 - I've seen examples where a tutorial says the value of 'this' would be window as the arrow function inherits from the global/window scope but I've also seen tutorials where they say it will inherit this from the class context - which is correct? if you could please explain.

class MyClass {
    value = 'Hello World!'
    clickHandler = () => { console.log(this.value) };
}

2 - I have 2 parts to this question - i - Why is the syntax clickHandler = () => rather than clickHandler () =>

I ask this because I read class methods can be defined with 'functionName () {}' so why do arrow functions treat the method name as a variable?

ii - What is the value of this in the below code? same as question 1 I guess, does this refer to the window object or the class?

class Foo extends React.Component {
  constructor() {
  }
  clickhandler = () => {
    console.log("you clicked me!!")
  }
  render() {
    return( 
    <div>
      <button onClick={this.clickhandler}> // => CALLBACK

3 - Here I see the event handler is an inline function, but it looks like it gets invoked because of the () at the end, sometimes as in the follow on snippet, you can see that just the function name is given without the parentheses, shouldn't they be there also?

class MyComponent extends React.Component {
  showValue() {
    console.log(this.props.value);
  }

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

-------------------------------------------

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

  render() {
    return (
      <button onClick={this.showValue}>Do Something</button>
    );
  }
like image 706
j obe Avatar asked Feb 23 '19 14:02

j obe


2 Answers

Why is the syntax clickHandler = () => rather than clickHandler () =>

foo () => ... syntax isn't valid for ES6 classes and this concept wouldn't make sense. foo() {...} is syntactic sugar for prototype method:

function Class() {}
Class.prototype.foo = function () {
  // this instanceof Class === true
}

This wouldn't work if Class.prototype.foo were an arrow; this would be retrieved from the scope where Class is defined:

// this === undefined

Class.prototype.foo = () => {
  // this === undefined
}

foo = () => ... is class field syntax, which is stage 3 proposal and not a part of ES6.

class Class {
  foo = () => {
    // this instanceof Class === true 
  }
}

is syntactic sugar for:

class Class {
  constructor() {
    // this instanceof Class === true 
    this.foo = () => {
      // this instanceof Class === true 
    }
  }
}

I've seen examples where a tutorial says the value of this would be window as the arrow function inherits from the global/window scope but I've also seen tutorials where they say it will inherit this from the class context/scope - which is correct?

Arrow function gets lexical this from enclosing scope. In case an arrow is defined in global scope, this is window, and undefined in ES module scope.

In the example above an arrow is defined in class constructor scope, this is class instance.

Here I see the event handler is an inline function, but it looks like it gets invoked because of the () at the end, sometimes as in the follow on snippet, you can see that just the function name is given without the parentheses, shouldn't they be there also?

Callback function is expected to be passed as onClick prop. this.showValue() calls a function and returns a value from it. Unless a value is a function, too, invoking a method in-place like onClick={this.showValue()} is incorrect.

onClick={this.showValue} passes class method as a callback. Since showValue is prototype method that isn't bound to proper this context, a callback will be executed with wrong context (the problem is explained in this question), while onClick={() => this.showValue()} passes wrapper function as a callback that executes showValue with correct context.

like image 141
Estus Flask Avatar answered Sep 22 '22 14:09

Estus Flask


1- this refers to current scope. In MyClass this refers to class instance. So the answer is both correct. In global scope this refers to the window, inside myclass this refers to the class.

2- As you may notice in arrow function there's no need to bind functions with the class, so there syntax is different.

3- onClick={() => this.showValue()}>Do Something</button> : creates a function each time click fires an event. It is useful when in some cases you want to pass extra args from component render to event handler.

onClick={() => this.showValue(event, id, name)}>Do Something</button>

but with onClick={this.showValue}>Do Something</button> which is the usual case, you call the handler when it fires an event without creating new function each time.

But how it can identifies the handler? By binding, this can recognize what is inside your scope because you are calling it inside which is showValue

like image 30
Jalal Avatar answered Sep 21 '22 14:09

Jalal