简体   繁体   中英

Is it possible to use arrow functions in classes with ES6?

My question is very simple. If I have a class in ES6 is it possible to use an arrow function within it?

import React, { Component } from 'react';

export default class SearchForm extends Component {

  state = {
    searchText: ''
  }

  onSearchChange = e => {
    this.setState({ searchText: e.target.value });
  }

  handleSubmit = e => {
    e.preventDefault();
    this.props.onSearch(this.query.value);
    e.currentTarget.reset();
  }

  render() {
    return (
      <form className="search-form" onSubmit={this.handleSubmit} >
        <label className="is-hidden" htmlFor="search">Search</label>
        <input type="search"
               onChange={this.onSearchChange}
               name="search"
               ref={(input) => this.query = input}
               placeholder="Search..." />
        <button type="submit" id="submit" className="search-button">
          <i className="material-icons icn-search">search</i>
        </button>
      </form>
    );
  }
}

The reason I ask is that I get an error in my console, even when using Babel. It seems like there's a lot of resources on the internet stating you can do this (most of which are about developing with React).

Is this something that Babel should do, and will eventually become natively supported?

The error I get is an unexpected = sign, just before the parens.

EDIT: I forgot to mention, the reason I wish to do this is to make use of the this keyword in context of the class. If I use a regular function - to my understanding - I would have to bind this to the function. I'm trying to look for a nicer way of doing that.

In order to do that, you'll need to add the transform-class-properties babel plugin, which allows you to have auto-bound class methods like you are attempting.

Unlike what others have just suggested, there IS value in doing this. Namely, your class function automatically has the class this bound to it, without having to manually bind it in your constructor.

Without the transform-class-properties plugin, you could do:

export default class SearchForm extends Component {

  constructor(props) {
    super(props)
    this.doSomething = this.doSomething.bind(this)
  }

  doSomething () {
    console.log(this) // <-- 'this' is the class instance
  }
}

With the plugin:

export default class SearchForm extends Component {

  doSomething = () => {
    console.log(this) // <-- 'this' is the class instance, no binding necessary
  }
}

Heres and article that explains it (among other thing) fairly well and consisely: https://medium.com/@joshblack/writing-a-react-component-in-es2015-a0b27e1ed50a

Yes it is possible to use arrow functions inside ES6 classes. I noticed that you are not calling super inside your constructor you have to do that if you are extending and overriding the constructor.

Other than that your code compiles correctly to ES5, checkout this link to the online Babel transpiler that contains your sample code.

Checkout this question similar to yours.

Yes, it is possible. Your code should work, you need to check you Babel setup, there must be something wrong with how it's configured.

In your example, doSomething is actually a property of the class; the type of the property is a function. Here's an example that additionally shows a method, as well as a use of the this keyword:

class SearchForm {

  doSomething = () => {
    console.log('I am a property')
  }

  doSomethingElse() {
    console.log('I am a method')
  }

  doBoth() {
    this.doSomething();
    this.doSomethingElse()
  }
}

const form = new SearchForm();
form.doBoth();

You can check it out live here .

Short answer to the post title : Yes you can, but you shouldn't. It's weird and bizarre to do that while using ES6 classes (long explanation below).

Correct solution to your specific use case : Since you want to call this.setState (which I supposed is defined in the parent class) from the object's instance, you should simply rewrite your onSearchChange as a class method:

onSearchChange(e){
    this.setState({ searchText: e.target.value });
  }

A little bit of theory

You are using ES6 classes. Classes have methods and properties/fields (among many other things). Instance methods are like class "functions", which (by definition) have access to the object's internal state. Methods can also call other methods, whether they are defined in the same class, or at some parent class in the inheritance chain. There's only one way to write class methods in ES6: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#prototype_methods .

Class properties/fields, on the other hand, are like "variables" which exists in every instance of a class. Every instance have it's own copy of it's properties/variables. In true OOP languages, instance variables can be declared as private or protected, which makes them completely inaccessible to the outside world. Class properties/fields, as any javascript variable, can hold ANY value, including.... "functions".

When you declare a "function" inside a ES6 class the way you did it, you are not declaring a class method, but declaring a class "field" which it's being assigned an initial value of: an arrow function ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#field_declarations ). This is already weird and bizarre, because it is not clear whether you wanted to declare a class method using arrow-function syntax (which is not possible, as previously explained), or you truly wanted to declare a class property/field, and have it automatically initialized to an arrow function... but in this case, why would you want to have every instance of the class with a copy of an arrow function, which, by definition, does't have access to the object's own this ? Wouldn't be better to have that function field declared as static? So you only have one copy of the arrow function? Or, even better: Why don't you simply move that function to the outside, and use a single reference to that function?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM