Isn't section 5.1 "Use object destructuring" conflicting with 3.3 "Use object method shorthand" ?
In section 5.1 it is stated the following:
Use object destructuring when accessing and using multiple properties of an object.
In section 3.3, it is stated the following:
Use object method shorthand.
Let's look at the following example:
const foo = {
bar: 5,
// applying 3.3
computeSomething() {
return this.bar + 5;
}
};
// applying 5.1
const {bar, computeSomething} = foo;
console.log(bar);
computeSomething();
The last instruction throws the following error:
TypeError: Cannot read properties of undefined (reading 'bar')
So, applying both 3.3 and 5.1 can lead to an incorrect code. Either we have to use arrow functions in objects definition; or we have to not use destructuring; but both 3.3 and 5.1 can't be recommended together without creating potential issues. At least, that's what I'm feeling.
What do you think? Did I miss the point or a clarification in the specs about that?
The incorrect code is the code using this in "not a class".
Make sense. Does it mean that destructuring section does not apply to class instances ?
Yep, exactly.
Can you explain the why ? Where do you draw the line between what is named Object in the documentation, and what you name Class instance? Aren't class instances objects?
Also, if there is a rule about class instances saying that they must not be destructured, how do you recommend that we actually know that we are destructuring a class instance?
Consider this:
service.mjs
export const service = new (class {
foo = 5;
doSomething() {
return this.foo;
}
});
index.mjs
import {doSomething} from "./service.mjs";
doSomething();
How are developers expected to know that what is exported by service.mjs is a class instance, and thus must not be destructured?
You always have to know what a thing you're importing is - without exception. Also, import { doSomething } is not destructuring, it's a named import, which is something quite different. Your example will throw.
Also, import { doSomething } is not destructuring, it's a named import, which is something quite different.
My example was wrong, sorry.
import {service} from "./service.mjs";
const {doSomething} = service;
doSomething();
You always have to know what a thing you're importing is - without exception.
So, we have to read the source code of everything that we import, this is the official AirBnb recommandations?
Also, I'm curious about what you mean by "You always have to know what a thing you're importing is".
The what is the type, the interface, the shape of the thing. It is not its implementation: this would be the how.
If I import something that is documented as of type Foo, I know what the thing is - a Foo.
So, do you mean that we MUST know how a thing that we import is implemented?
It's not just an airbnb recommendation - in all programming, everywhere, without exception, you have to know what you're importing. You can do that by reading docs, by reading the source code, or by playing around in a repl, but you still must know.
If a function depends on its receiver in JavaScript, that's something you simply have to know "somehow", or you won't be able to use it properly.
in all programming, everywhere, without exception, you have to know what you're importing
Yes, what. Not how.
You can do that by reading docs, by reading the source code, or by playing around in a repl, but you still must know.
The docs give the what. Now, I see that you recommend that we read the source code of every single library that we use, or play around with it on a repl. I think it is time for me to end this conversation then.
That's not what I'm recommending - the docs would count too, and yes, that is how programming works - you can't use something if you don't have some expectation of what interface and semantics it has.
How you import it is the same regardless of which method you use - const {doSomething} = service; is the problem, and that's not an import.
const foo = { bar: 5,
computeSomething() { return this.bar + 5; } };
console.log("Direct call:", foo.computeSomething()); // 10
const { bar, computeSomething } = foo; console.log("Destructured bar:", bar); // 5 try { console.log("Destructured computeSomething:", computeSomething()); // NaN or error } catch (e) { console.log("Error:", e.message); }
const boundCompute = foo.computeSomething.bind(foo); console.log("Bound function:", boundCompute()); // 10
const fooArrow = { bar: 5, computeSomething: () => this.bar + 5 };
console.log("Arrow function call:", fooArrow.computeSomething()); // NaN
// we have to bind it foo then only it will show either it iwll show error right