Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with "Arrow function expressions": Can be used to define methods #11237

Closed
alattalatta opened this issue Dec 15, 2021 · 7 comments · Fixed by #18147
Closed

Issue with "Arrow function expressions": Can be used to define methods #11237

alattalatta opened this issue Dec 15, 2021 · 7 comments · Fixed by #18147
Labels
Content:JS JavaScript docs effort: small This task is a small effort. help wanted If you know something about this topic, we would love your help!

Comments

@alattalatta
Copy link
Member

alattalatta commented Dec 15, 2021

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

What information was incorrect, unhelpful, or incomplete?

Does not have its own bindings to this or super, and should not be used as methods.

Indeed arrow functions are not suitable for methods on a plain JS objects as one of the doc's examples:

const a = {
  b: () => console.log(this), // Window or undefined
}

But when used within a class definition, I can use it to define methods (with a help of public class fields which modern browsers are supporting).

class A {
  b = () => { console.log(this) } // A
}
const a = new A()

Even though it isn't the classic method (can't be extended because no super), some prefer this syntax for classes that won't be extended, to avoid having to bind class methods manually when passing them as parameters. It's more relevant to JSX codebases where you have to pass methods as component props.

<Button onClick={a.b} />
{/* vs. */}
<Button onClick={a.b.bind(a)} />
{/* vs. */}
<Button onClick={() => a.b()} />

And the A.prototype.b is still considered a method: It belongs to an object (class instance) and it has its this set to the object.

Specific section or headline?

The intro.

What did you expect to see?

Other than "should not be used as methods".

Did you test this? If so, how?

Ran the code blocks I've written above.

MDN Content page report details
@alattalatta alattalatta changed the title Issue with "Arrow function expressions": (short summary here please) Issue with "Arrow function expressions": Can be used to define methods Dec 15, 2021
@github-actions github-actions bot added the needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. label Dec 15, 2021
@Andrew-Cottrell
Copy link

Andrew-Cottrell commented Dec 15, 2021

And the A.prototype.b is still considered a method

The described approach defines an instance field rather than an instance method.

class A {
  b = () => { console.log(this) }
}

console.log(typeof A.prototype.b); // "undefined"
console.log(typeof new A().b);     // "function"

/* in the following an instance method would log {foo: "bar"} */
new A().b.call({foo: "bar"});   // A {b: ƒ}
new A().b.apply({foo: "bar"});  // A {b: ƒ}
new A().b.bind({foo: "bar"})(); // A {b: ƒ} 

The field's value might be a function that may be called as-a-method, but it doesn't match what people usually mean when talking about either static methods or instance methods. I suppose we could call it a pseudo-method, but it's probably for the best if MDN continues to keep things simple with the "should not be used as methods" recommendation.

@sideshowbarker sideshowbarker added Content:JS JavaScript docs effort: small This task is a small effort. help wanted If you know something about this topic, we would love your help! and removed needs triage Triage needed by staff and/or partners. Automatically applied when an issue is opened. labels Dec 15, 2021
@tabatkins
Copy link

Right, that is not at all a method; the this binding visible to it is the class itself (or something like that; I don't know the details), established by the binding environment for evaluating field definitions, and is completely unrelated to a method-like this that can be set at runtime by the call syntax or the meta-calling methods.

@ljharb
Copy link
Contributor

ljharb commented Dec 15, 2021

"method" isn't a universally agreed-upon term.

I'd say a method is a function that behaves differently depending on its receiver (the this value), and thus an arrow function nor a bound function are eligible to ever be a method.

@ljharb
Copy link
Contributor

ljharb commented Dec 15, 2021

Using arrow functions in public fields is a hacky, subpar way to fake having a regular method that's also auto-bound to instances. Here's how I'd do that now:

foo = this.foo.bind(this);
foo() {}

and here's how i'd do that when decorators are a thing:

@bound
foo() {}

@js-choi
Copy link
Contributor

js-choi commented Dec 16, 2021

I'd say a method is a function that behaves differently depending on its receiver (the this value), and thus an arrow function nor a bound function are eligible to ever be a method.

For what it’s worth, the language specification itself uses the term “method” on functions that do not use the this binding, such as Object.values. Although in general it seems to prefer the clearer term “function properties”.

@ljharb
Copy link
Contributor

ljharb commented Dec 16, 2021

The language specification uses a bunch of internal terms that don't precisely match colloquial usage - the editors are in fact currently discussing defining the term "method" and consistently using (or not using) the term. Either way, the spec's terminology should document reality, and shouldn't define it.

@alattalatta
Copy link
Member Author

I agree that it's hacky, I'd prefer auto-bind which is basically what @ljharb wrote. Or I just avoid using classes at all.

And to come to think of it, I also agree with this:

I'd say a method is a function that behaves differently depending on its receiver (the this value), and thus an arrow function nor a bound function are eligible to ever be a method.


But then, if public class fields + arrow functions should be thought as an anti-pattern, I think this might deserve its own explanation, and/or clearer way of definition for the term, method. Searching "react class method binding" yields quite a lot of articles which list the pattern as a way to avoid manual binding. (Disclaimer: They don't usually explicitly claim the fields as "methods" at least... but they look like methods!)

From Method glossary:

A method is a function which is a property of an object. There are two kind of methods: Instance Methods which are built-in > tasks performed by an object instance, or Static Methods which are tasks that are called directly on an object constructor.

A public class field that happens to be a function is a function which is a property of an object. Is it not? This page may be used to state that bound functions and arrow functions can't be methods and reasons for it.

The spec also defines methods as nothing but a function property on an object ("function that is the value of a property") - but if they are discussing it, great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Content:JS JavaScript docs effort: small This task is a small effort. help wanted If you know something about this topic, we would love your help!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants