Skip to content

Commit e713fef

Browse files
committed
js-style-guide update
1 parent 6ac10bd commit e713fef

File tree

1 file changed

+45
-121
lines changed
  • website/docs/developer/js-style-guide

1 file changed

+45
-121
lines changed

website/docs/developer/js-style-guide/index.mdx

Lines changed: 45 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ projects will be migrated to TypeScript.
2727

2828
After many years of working with style guides for various languages,
2929
the conclusion is that the specific style is of lesser importance;
30-
what matters more is its consistent application.
30+
what matters more is its **consistent application**.
3131

32-
To ensure consistency in the xPack JavaScript source files, the
32+
To ensure consistency in the xPack JavaScript/TypeScript source files, the
3333
primary requirements are:
3434

3535
- use [prettier](https://prettier.io) for automated re-formatting
@@ -252,10 +252,20 @@ Array.isArray([1, 2, 3]); // true
252252

253253
```js
254254
isString (x) {
255-
return Object.prototype.toString.call(x) === '[object String]'
255+
return typeof value === 'string'
256256
}
257257
```
258258

259+
:::note
260+
261+
The previous recommandation was to use
262+
`Object.prototype.toString.call(x) === '[object String]'`, needed to
263+
distinguish between primitive strings ('hello') and `String` objects
264+
(new String('hello')), but `String` objects are rarely used in modern
265+
JavaScript and are generally considered an anti-pattern.
266+
267+
:::
268+
259269
### Check if object
260270

261271
```js
@@ -281,38 +291,7 @@ the specifications do not guarantee the insert order to be preserved.
281291
If the order is important, or if the object needs to store other
282292
properties too, use a `Map`.
283293

284-
### Make node exports/imports look like ES6 exports/imports
285-
286-
Assuming classes are preferred, the EC6 syntax for export/import would look like:
287-
288-
```js
289-
export class WscriptAvoider { ... }
290-
...
291-
import { WscriptAvoider } from 'wscript-avoider.js'
292-
```
293-
294-
So, to stay close to this syntax, the recommendation is to preserve the
295-
original `module.exports` object, and add properties to it, preferably
296-
classes, even if they have only static members.
297-
298-
To import them, the syntax uses the explicit class name:
299-
300-
```js
301-
const WscriptAvoider = require('wscript-avoider').WscriptAvoider
302-
WscriptAvoider.quitIfWscript(appName)
303-
```
304-
305-
Cases like `import { WscriptAvoider as Xyz } from 'wscript-avoider.js'` would
306-
be naturally represented as:
307-
308-
```js
309-
const Xyz = require('wscript-avoider').WscriptAvoider
310-
Xyz.quitIfWscript(appName)
311-
```
312-
313-
In case the class is not static, instantiate it as usual.
314-
315-
### Call exactly the class method
294+
### Call the class method via the prototype
316295

317296
If a method of a class is overridden, calling it from the base class
318297
actually calls the derived method (run-time polymorphism).
@@ -331,20 +310,27 @@ class Base {
331310
}
332311
```
333312

334-
### Pack function parameters as objects
313+
### Destructured parameters
335314

336315
For functions with more than 1 parameter, pack them in an object:
337316

338-
```js
317+
```ts
339318
class Base {
340319
/**
341-
* @param {Object} params The generic parameters object.
320+
* @params name The object name.
321+
* @params type The object type
322+
* @returns Nothing
342323
*/
343-
f1 (params) {
344-
assert(params, 'There must be params.')
345-
324+
f1 ({
325+
name,
326+
type
327+
}: {
328+
name: string
329+
type: string
330+
}): void {
346331
assert(params.name)
347332
console.log(params.name)
333+
// ...
348334
}
349335

350336
f2 () {
@@ -368,19 +354,22 @@ references are cleared (set to undefined).
368354

369355
Alternatively use `copyFrom(from)` and possibly `appendFrom(from)`.
370356

371-
Use a `clear()` method to clear the object content (it might be
372-
useful during tests).
357+
Use a `clear()` method to clear the object content (it might also be
358+
useful during testing).
373359

374-
### Use a separate location for private variables
360+
### Use the `#` prefix for private members.
375361

376-
To reduce clutter, group the private variables below a `_private` object.
362+
According to recent standard updates, names starting with `#` are private.
377363

378-
No need to end the name of the variables with `_`.
364+
### Use the `_` prefix for private members.
365+
366+
Similarly, although this is not part of any standard, use names starting
367+
with `_` for the protected members.
379368

380369
### Use a separate location for cached variables
381370

382371
If the object uses local cached objects, group them below a `_cache` object.
383-
Initialise it to an empty object in the constructor an in the `clear()` method.
372+
Initialise it to an empty object in the constructor and in the `clear()` method.
384373

385374
No need to end the name of the variables with `_`.
386375

@@ -460,8 +449,14 @@ console.log(add(1, 1)) // 2
460449
console.log(add(1)) // 2
461450
```
462451

463-
JavaScript has two different internal-only methods for functions: `[[Call]]` and `[[Construct]]`. When a function is called without new, the `[[Call]]` method is executed, which executes the body of the function as it appears in the code. When a function is called with new, that’s when the `[[Construct]]` method
464-
is called. The `[[Construct]]` method is responsible for creating a new object, called the instance, and then executing the function body with this set to the instance. Functions that have a `[[Construct]]` method are called constructors.
452+
JavaScript has two different internal-only methods for functions:
453+
`[[Call]]` and `[[Construct]]`. When a function is called without new,
454+
the `[[Call]]` method is executed, which executes the body of the function
455+
as it appears in the code. When a function is called with new, that’s when
456+
the `[[Construct]]` method is called. The `[[Construct]]` method is
457+
responsible for creating a new object, called the instance, and then
458+
executing the function body with this set to the instance. Functions
459+
that have a `[[Construct]]` method are called constructors.
465460

466461
```js
467462
const Person = function (name) {
@@ -608,77 +603,6 @@ However, for the modern ES 6 promise usage, exceptions are acceptable.
608603

609604
## From [Node.js modules](https://nodejs.org/dist/latest-v6.x/docs/api/modules.html)
610605

611-
### Modules
612-
613-
Modules are a way of preventing multiple JavaScript units to pollute the global namespace.
614-
615-
Objects defined at root level in a module are not global, but belong to the module; the usual name for this is _module-global_.
616-
617-
### Caching
618-
619-
Modules are cached after the first time they are loaded. This means (among other things) that every call to require('foo') will get exactly the same object returned, if it would resolve to the same file. Multiple calls to `require('foo')` will not cause the module code to be executed multiple times.
620-
621-
From this point of view, modules behave like [singletons](https://en.wikipedia.org/wiki/Singleton_pattern); they can also be compared to static classes in C++.
622-
623-
Leaving state at the module level can be either a blessing or a curse, depending on the environment used to run the module. In server environments, using module-global variables is like using static variables in a multi-threaded environment; if not handled correctly, it may have unexpected results.
624-
625-
### Exports
626-
627-
To make some functions and objects visible outside the module, add them as properties to the special `module.exports` object:
628-
629-
```js
630-
const PI = Math.PI
631-
module.exports.area = (r) => PI * r * r
632-
module.exports.circumference = (r) => 2 * PI * r
633-
```
634-
635-
Although you can rewrite the `module.exports` to be a single function (such as a constructor), it is still preferable to add them as properties to the object and refer to them explicitly in the `require()` line:
636-
637-
```js
638-
const square = require('./square.js').square
639-
const mySquare = square(2)
640-
console.log(`The area of my square is ${mySquare.area()}`)
641-
642-
module.exports.area = (width) => {
643-
return {
644-
area: () => width * width
645-
}
646-
}
647-
```
648-
649-
If you want to export a complete object in one assignment instead of building it one property at a time, assign it to `module.exports`.
650-
651-
### Accessing the main module
652-
653-
When a file is run directly from Node.js, `require.main` is set to its module. That means that you can determine whether a file has been run directly by testing
654-
655-
```js
656-
require.main === module
657-
```
658-
659-
### The module wrapper (deprecated by ES6)
660-
661-
Before a module's code is executed, Node.js will wrap it with a function wrapper that looks like the following:
662-
663-
```js
664-
module = ... // an object for the current module
665-
module.exports = {} // an empty object
666-
exports = module.exports // a reference to the exports; avoid using it
667-
__filename = '/x/y/z/abc.js'
668-
__dirname = '/x/y/z'
669-
(function (exports, require, module, __filename, __dirname) {
670-
// The module code actually lives in here
671-
});
672-
```
673-
674-
In each module, the `module` variable is a reference to the object representing the current module. `module` is not actually a global but rather local to each module.
675-
676-
The `module.exports` object is created by the Module system. Sometimes this is not acceptable; many developers want their module to be an object of their own. To do this, assign the desired export object to `module.exports`.
677-
678-
For convenience, `module.exports` is also accessible via the `exports` module-global. Note that assigning a value to `exports` will simply rebind the local exports variable, which is probably not what you want to do; if the relationship between `exports` and `module.exports` seems like magic to you, ignore `exports` and only use `module.exports`.
679-
680-
Note that assignment to `module.exports` must be done immediately. It cannot be done in any callbacks.
681-
682606
### Global objects
683607

684608
These are really objects, available in all modules. (see Node.js [Globals](https://nodejs.org/api/globals.html))
@@ -693,7 +617,7 @@ These are really objects, available in all modules. (see Node.js [Globals](https
693617

694618
## The Spread syntax
695619

696-
According to [JavaScript ES6— The Spread Syntax (…)](https://codeburst.io/javascript-es6-the-spread-syntax-f5c35525f754):
620+
According to [JavaScript ES6 — The Spread Syntax (…)](https://codeburst.io/javascript-es6-the-spread-syntax-f5c35525f754):
697621

698622
- The spread syntax is simply three dots: `...`
699623
- It allows an iterable to expand in places where 0+ arguments are expected.

0 commit comments

Comments
 (0)