144

I'm using babel6 and for my pet project I'm creating a wrapper for XMLHttpRequest, for the methods I can use:

open = (method, url, something) => {
  return this.xhr.open(method, url, something);
}

but for the properties arrow function doesn't work

this works:

get status() { return this.xhr.status; }

but I can not use

get status = () => this.xhr.status;

Is this intentional?

Gabor Dolla
  • 2,352
  • 4
  • 13
  • 11
  • You don't need the curly brackets or the return; you can just say `(method, url, something) => this.xhr.open(method. url, something)`. –  Nov 20 '15 at 14:06
  • `get` is a part of an object literal or a class definition, a variable assignment is not. Why do you think they should work alike? – Bergi Nov 20 '15 at 14:22
  • 4
    ```status => this.xhr.status``` (c# 7 syntaxe) or maybe ```get status() => this.xhr.status```would indeed have been a great syntaxic sugar for readability but Javascript not Typescript doesn't (yet?) support it – Charles HETIER May 28 '19 at 15:01
  • I need this so much in my life!!! – Cristian E. Aug 30 '21 at 12:34

2 Answers2

160

According to the ES2015 grammar, a property on an object literal can only be one of three things:

PropertyDefinition:

  • IdentifierReference
  • PropertyName : AssignmentExpression
  • MethodDefinition

The only one of these type that allows a leading get is MethodDefinition:

MethodDefinition :

  • PropertyName ( StrictFormalParameters ) { FunctionBody }
  • GeneratorMethod
  • get PropertyName ( ) { FunctionBody }
  • set PropertyName ( PropertySetParameterList ) { FunctionBody }

As you can see, the get form follows a very limited grammar that must be of the form

get NAME () { BODY }

The grammar does not allow functions of the form get NAME = ....

FreeAsInBeer
  • 12,891
  • 5
  • 48
  • 80
apsillers
  • 107,868
  • 16
  • 221
  • 236
  • Thanks for your help, I accept your answer. Do you know where it's defined that getter/setter can not be used with an assignment ? Just curious. – Gabor Dolla Nov 20 '15 at 13:20
  • @GaborDolla Edited to refer to the object literal grammar in the ECMAScript spec. – apsillers Nov 20 '15 at 13:31
56

The accepted answer is great. It's the best if you're willing to use normal function syntax instead of compact "arrow function syntax".

But maybe you really like arrow functions; maybe you use the arrow function for another reason which a normal function syntax cannot replace; you may need a different solution.

For example, I notice OP uses this, you may want to bind this lexically; aka "non-binding of this"), and arrow functions are good for that lexical binding.

You can still use an arrow function with a getter via the Object.defineProperty technique.

{
  ...
  Object.defineProperty(your_obj, 'status', { 
     get : () => this.xhr.status 
  });
  ...
}

See mentions of object initialization technique (aka get NAME() {...}) vs the defineProperty technique (aka get : ()=>{}). There is at least one significant difference, using defineProperty requires the variables already exists:

Defining a getter on existing objects

i.e. with Object.defineProperty you must ensure that your_obj (in my example) exists and is saved into a variable (whereas with a object-initialization you could return an object-literal in your object initialization: {..., get(){ }, ... }). More info on Object.defineProperty specifically, here

Object.defineProperty(...) seems to have comparable browser support to the get NAME(){...} syntax; modern browsers, IE 9.

The Red Pea
  • 14,933
  • 15
  • 89
  • 118
  • 15
    Clever, but it's ultimately much more verbose than just: `get status() { return this.xhr.status; }` – devuxer Feb 24 '18 at 01:23
  • 7
    @devuxer I agree it's too verbose. But just to be clear, your `this` *must* be the object in which your `get status() { ... }` is defined. But *my* `this` *could* be something else, due to lexical binding differences, right? – The Red Pea Feb 24 '18 at 17:54
  • 3
    Agree...though in practice, I haven't run into a case where `this` isn't what I want in a get accessor. (The `this` binding benefits of arrow functions seem to come into play when passing functions around, as with event handlers and callbacks.) – devuxer Feb 26 '18 at 20:37
  • 4
    I agree, I frequently use fat arrow + lexical bindings `()=>{}` for the callbacks I pass to a **Promise**, like `$http(...).then((promise_result)=> this...}))`. If I don't use fat-arrow, `this` will represent the global `Window` object; not very useful. But I seldom (never?) have used `()=>{}` as the function for a "get accessor" as you say... at least `this` inside of `get()` will represent the object on which `get()` is defined (which is already more useful than `Window`; so there's no need to use a fat-arrow function!) – The Red Pea Feb 26 '18 at 20:48
  • 1
    The `defineProperty` approach is useful in loops. Right now I just used it to expose some properties of a chiled object from the containing one. – Edurne Pascual Oct 17 '20 at 11:24
  • 1
    Very useful. I used this approach to define some field of an object that was depending on values on the containing object (a class object more precisely). So I had to use `this` as a reference to the class object which declared the variable. However for unknown reasons these properties where not returned by `Object.keys(my_object)` – Bemipefe Nov 21 '20 at 17:46
  • 1
    @Bemipefe, Object.keys will list your property if you define the property like this; notice we explicitly set the value of the `enumerable` argument to **true** (if omitted, [`enumerable` defaults to **false**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty#Description)) `my_object = {}; Object.defineProperty(my_object, 'prop', { get: ()=>'val', enumerable: true }); Object.keys(my_object);` – The Red Pea Nov 23 '20 at 02:33