Skip to content

Petrosdevri/javascript-style-guide

Repository files navigation

Airbnb Αισθητικός Οδηγός JavaScript() {

Μια περισσότερο λογική προσέγγιση της JavaScript

Σημείωση: αυτός ο οδηγός προϋποθέτει ότι χρησιμοποιείτε το Babel, και απαιτεί τη χρήση του babel-preset-airbnb ή του αντιστοίχου. Προϋποθέτει επίσης ότι εγκαθιστάτε shims/polyfills στην εφαρμογή σας, με airbnb-browser-shims ή το αντίστοιχο.

Downloads Downloads Gitter

Ο οδηγός είναι διαθέσιμος και σε άλλες γλώσσες. Δείτε τη Μετάφραση.

Άλλοι Αισθητικοί Οδηγοί

Πίνακας Περιεχομένων

  1. Tύποι (Types)
  2. Αναφορές
  3. Αντικείμενα (Objects)
  4. Πίνακες (Arrays)
  5. Αποδόμηση (Destructuring)
  6. Συμβολοσειρές (Strings)
  7. Συναρτήσεις (Functions)
  8. Συναρτήσεις Βέλους (Arrow Functions)
  9. Κλάσεις & Κατασκευαστές (Classes & Constructors)
  10. Ενότητες (Modules)
  11. Επαναλήπτες & Γενικευτές (Iterators & Generators)
  12. Ιδιότητες (Properties)
  13. Μεταβλήτές (Variables)
  14. Ανύψωση (Hoisting)
  15. Τελεστές Σύγκρισης & Ισότητα (Comparison Operators & Equality)
  16. Μπλοκ (Blocks)
  17. Δηλώσεις Ελέγχου (Control Statements)
  18. Σχόλια (Comments)
  19. Κενός Χώρος (Whitespace)
  20. Κόμματα (Commas)
  21. Ερωτηματικά (Semicolons)
  22. Casting Τύπων & Καταναγκασμός (Type Casting & Coercion)
  23. Συμβάσεις Ονομασίας (Naming Conventions)
  24. Στοιχεία Πρόσβασης (Accessors)
  25. Γεγονότα (Events)
  26. jQuery
  27. Συμβατότητα ECMAScript 5
  28. Στυλ ECMAScript 6+ (ES 2015+)
  29. Αρχική Βιβλιοθήκη (Standard Library)
  30. Δοκιμές (Testing)
  31. Απόδοση (Performance)
  32. Πηγές
  33. Στα Άγρια
  34. Μετάφραση
  35. Ο Οδηγός του Αισθητικού Οδηγού της JavaScript
  36. Συνομιλήστε Μαζί Μας Σχετικά Με Τη JavaScript
  37. Συνεισφέροντες
  38. Άδεια
  39. Τροπολογίες

Tύποι (Types)

  • 1.1 Πρωταρχικοί: Όταν αποκτάτε πρόσβαση σε έναν πρωταρχικό τύπο δουλεύετε κατευθείαν με την αξία του.

    • string
    • number
    • boolean
    • null
    • undefined
    • symbol
    • bigint

    const foo = 1;
    let bar = foo;
    
    bar = 9;
    
    console.log(foo, bar); // => 1, 9
    • Τα Σύμβολα (Symbols) και οι Μεγάλοι Ακέραιοι Αριθμοί (BigInts) δεν μπορούν να συμπληρωθούν πιστά, επομένως δεν πρέπει να χρησιμοποιούνται κατά τη στόχευση προγραμμάτων περιήγησης/περιβάλλοντος που δεν τα υποστηρίζουν εγγενώς.

  • 1.2 Σύνθετοι: Όταν αποκτάτε πρόσβαση σε έναν σύνθετο τύπο, εργάζεστε σε μια αναφορά στην τιμή του.

    • object
    • array
    • function

    const foo = [1, 2];
    const bar = foo;
    
    bar[0] = 9;
    
    console.log(foo[0], bar[0]); // => 9, 9

⬆ Πίσω στην κορυφή

Αναφορές

  • 2.1 Χρησιμοποιήστε const για όλες τις αναφορές σας; αποφύγετε τη χρήση του var. eslint: prefer-const, no-const-assign

    Γιατί; Αυτό διασφαλίζει ότι δεν μπορείτε να αναθέσετε ξανά τις αναφορές σας, κάτι που μπορεί να οδηγήσει σε σφάλματα και δυσνόητο κώδικα.

    // bad
    var a = 1;
    var b = 2;
    
    // good
    const a = 1;
    const b = 2;

  • 2.2 Εάν πρέπει να εκχωρήσετε εκ νέου αναφορές, χρησιμοποιήστε let αντί του var. eslint: no-var

    Γιατί; Το let έχει εύρος μπλοκ (block-scoped) αντί για συνάρτησης (function-scoped) όπως το var.

    // κακό
    var count = 1;
    if (true) {
      count += 1;
    }
    
    // καλό, χρησιμοποιήστε το let.
    let count = 1;
    if (true) {
      count += 1;
    }

  • 2.3 Σημειώστε ότι και το let και το const έχουν εύρος μπλοκ, ενώ το var έχει εύρος συνάρτησης.

    // το const και το let υπάρχουν μόνο στα μπλοκ στα οποία έχουν καθοριστεί.
    {
      let a = 1;
      const b = 1;
      var c = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError
    console.log(c); // Δίνει 1

    Στον παραπάνω κώδικα, μπορείτε να δείτε ότι η αναφορά a and b θα παράγει ένα Λάθος Αναφοράς (ReferenceError), ενώ το c περιέχει τον αριθμό. Αυτό οφείλεται στο ότι το a και το b έχουν εύρος μπλοκ (block scoped), ενώ το c καλύπτεται από τη συνάρτηση όπου βρίσκεται.

⬆ Πίσω στην κορυφή

Αντικείμενα (Objects)

  • 3.1 Χρησιμοποιήστε την κυριολεκτική σύνταξη (literal syntax) για τη δημιουργία αντικειμένων. eslint: no-new-object

    // κακό
    const item = new Object();
    
    // καλό
    const item = {};

  • 3.2 Χρησιμοποιήστε υπολογισμένα ονόματα ιδιοτήτων κατά τη δημιουργία αντικειμένων με ονόματα δυναμικών ιδιοτήτων.

    Γιατί; Σας επιτρέπουν να ορίσετε όλες τις ιδιότητες ενός αντικειμένου σε ένα μέρος.

    function getKey(k) {
      return `a key named ${k}`;
    }
    
    // κακό
    const obj = {
      id: 5,
      name: 'San Francisco',
    };
    obj[getKey('enabled')] = true;
    
    // καλό
    const obj = {
      id: 5,
      name: 'San Francisco',
      [getKey('enabled')]: true,
    };

  • 3.3 Χρησιμοποιήστε τη συντομογραφία της μεθόδου αντικειμένου (object method shorthand). eslint: object-shorthand

    // κακό
    const atom = {
      value: 1,
    
      addValue: function (value) {
        return atom.value + value;
      },
    };
    
    // καλό
    const atom = {
      value: 1,
    
      addValue(value) {
        return atom.value + value;
      },
    };

  • 3.4 Χρησιμοποιήστε τη συντομογραφία της αξίας της ιδιότητας (property value shorthand). eslint: object-shorthand

    Γιατί; Είναι πιο σύντομο και περιγραφικό.

    const lukeSkywalker = 'Luke Skywalker';
    
    // κακό
    const obj = {
      lukeSkywalker: lukeSkywalker,
    };
    
    // καλό
    const obj = {
      lukeSkywalker,
    };

  • 3.5 Ομαδοποιήστε τις συντομογραφικές σας ιδιότητες (shorthand properties) στην αρχή της δήλωσης του αντικειμένου σας.

    Γιατί; Είναι πιο εύκολο να πούμε ποιες ιδιότητες χρησιμοποιούν τη στενογραφία.

    const anakinSkywalker = 'Anakin Skywalker';
    const lukeSkywalker = 'Luke Skywalker';
    
    // κακό
    const obj = {
      episodeOne: 1,
      twoJediWalkIntoACantina: 2,
      lukeSkywalker,
      episodeThree: 3,
      mayTheFourth: 4,
      anakinSkywalker,
    };
    
    // καλό
    const obj = {
      lukeSkywalker,
      anakinSkywalker,
      episodeOne: 1,
      twoJediWalkIntoACantina: 2,
      episodeThree: 3,
      mayTheFourth: 4,
    };

  • 3.6 Αναφέρετε μόνο ιδιότητες που δεν είναι έγκυρα αναγνωριστικά. eslint: quote-props

    Γιατί; Γενικά θεωρούμε ότι είναι υποκειμενικά πιο εύκολο να διαβαστεί. Βελτιώνει την επισήμανση σύνταξης και επίσης βελτιστοποιείται πιο εύκολα από πολλές μηχανές JS.

    // κακό
    const bad = {
      'foo': 3,
      'bar': 4,
      'data-blah': 5,
    };
    
    // καλό
    const good = {
      foo: 3,
      bar: 4,
      'data-blah': 5,
    };

  • 3.7 Μη καλέστε τις μεθόδους του Object.prototype αμέσως, όπως hasOwnProperty, propertyIsEnumerable, και isPrototypeOf. eslint: no-prototype-builtins

    Γιατί; Αυτές οι μέθοδοι ενδέχεται να επισκιάζονται από ιδιότητες του εν λόγω αντικειμένου - σκεφτείτε { hasOwnProperty: false } - ή, το αντικείμενο μπορεί να είναι ένα μηδενικό αντικείμενο (null object) (Object.create(null)).

    // κακό
    console.log(object.hasOwnProperty(key));
    
    // καλό
    console.log(Object.prototype.hasOwnProperty.call(object, key));
    
    // άριστο
    const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope.
    console.log(has.call(object, key));
    /* or */
    import has from 'has'; // https://www.npmjs.com/package/has
    console.log(has(object, key));
    /* or */
    console.log(Object.hasOwn(object, key)); // https://www.npmjs.com/package/object.hasown

  • 3.8 Προτιμήστε τη σύνταξη spread (spread syntax) από τη μέθοδο Object.assign για να αντιγράψετε ρηχά αντικείμενα. Χρησιμοποιήστε τη σύνταξη παραμέτρου rest (rest parameter syntax) για να λάβετε ένα νέο αντικείμενο με ορισμένες ιδιότητες να παραλείπονται. eslint: prefer-object-spread

    // πολύ κακό
    const original = { a: 1, b: 2 };
    const copy = Object.assign(original, { c: 3 }); // this mutates `original` ಠ_ಠ
    delete copy.a; // so does this
    
    // κακό
    const original = { a: 1, b: 2 };
    const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
    
    // καλό
    const original = { a: 1, b: 2 };
    const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
    
    const { a, ...noA } = copy; // noA => { b: 2, c: 3 }

⬆ Πίσω στην κορυφή

Πίνακες (Arrays)

  • 4.1 Χρησιμοποιήστε τη κυριολεκτική σύνταξη (literal syntax) για δημιουργία πινάκων. eslint: no-array-constructor

    // κακό
    const items = new Array();
    
    // καλό
    const items = [];

  • 4.2 Χρησιμοποιήστε τη μέθοδο Array#push αντί για άμεση ανάθεση για να προσθέσετε στοιχεία σε έναν πίνακα.

    const someStack = [];
    
    // κακό
    someStack[someStack.length] = 'abracadabra';
    
    // καλό
    someStack.push('abracadabra');

  • 4.3 Χρησιμοποιήστε τη σύνταξη spread ... για να αντιγράψετε πίνακες.

    // κακό
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i += 1) {
      itemsCopy[i] = items[i];
    }
    
    // καλό
    const itemsCopy = [...items];

  • 4.4 Για να μετατρέψετε ένα επαναληπτικό αντικείμενο (iterable object) σε πίνακα, χρησιμοποιήστε τη σύνταξη spread ... αντί για τη μέθοδο Array.from

    const foo = document.querySelectorAll('.foo');
    
    // καλό
    const nodes = Array.from(foo);
    
    // άριστο
    const nodes = [...foo];

  • 4.5 Χρησιμοποιήστε τη μέθοδο Array.from για τη μετατροπή ενός αντικειμένου που μοιάζει με πίνακα σε πίνακα.

    const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 };
    
    // κακό
    const arr = Array.prototype.slice.call(arrLike);
    
    // καλό
    const arr = Array.from(arrLike);

  • 4.6 Χρησιμοποιήστε τη μέθοδο Array.from αντί για τη σύνταξη spread ... για αντιστοίχιση επαναλήψεων, επειδή αποφεύγει τη δημιουργία ενδιάμεσου πίνακα.

    // κακό
    const baz = [...foo].map(bar);
    
    // κακό
    const baz = Array.from(foo, bar);

  • 4.7 Χρησιμοποιήστε δηλώσεις επιστροφής (return statements) σε επανακλήσεις μεθόδων πίνακα (array method callbacks). Είναι εντάξει να παραλείψετε την επιστροφή εάν το σώμα συνάρτησης αποτελείται από μια μεμονωμένη πρόταση που επιστρέφει μια έκφραση χωρίς παρενέργειες, 8.2. eslint: array-callback-return

    // καλό
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });
    
    // καλό
    [1, 2, 3].map((x) => x + 1);
    
    // κακό - καμία επιστρεφόμενη αξία σημαίνει ότι το `acc` γίνεται undefined μετά τη πρώτη επανάληψη
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
      const flatten = acc.concat(item);
    });
    
    // καλό
    [[0, 1], [2, 3], [4, 5]].reduce((acc, item, index) => {
      const flatten = acc.concat(item);
      return flatten;
    });
    
    // κακό
    inbox.filter((msg) => {
      const { subject, author } = msg;
      if (subject === 'Mockingbird') {
        return author === 'Harper Lee';
      } else {
        return false;
      }
    });
    
    // καλό
    inbox.filter((msg) => {
      const { subject, author } = msg;
      if (subject === 'Mockingbird') {
        return author === 'Harper Lee';
      }
    
      return false;
    });

  • 4.8 Χρησιμοποιήστε αλλαγές γραμμής μετά το άνοιγμα και πριν κλείσετε αγκύλες πίνακα εάν ένας πίνακας έχει πολλές γραμμές.

    // bad
    const arr = [
      [0, 1], [2, 3], [4, 5],
    ];
    
    const objectInArray = [{
      id: 1,
    }, {
      id: 2,
    }];
    
    const numberInArray = [
      1, 2,
    ];
    
    // good
    const arr = [[0, 1], [2, 3], [4, 5]];
    
    const objectInArray = [
      {
        id: 1,
      },
      {
        id: 2,
      },
    ];
    
    const numberInArray = [
      1,
      2,
    ];

⬆ Πίσω στην κορυφή

Αποδόμηση (Destructuring)

  • 5.1 Χρησιμοποιήστε την αποδόμηση αντικειμένου (object destructuring) κατά την πρόσβαση και χρήση πολλαπλών ιδιοτήτων ενός αντικειμένου. eslint: prefer-destructuring

    Γιατί; Η αποδόμηση σάς εξοικονομεί από τη δημιουργία προσωρινών αναφορών για αυτές τις ιδιότητες και από την επαναλαμβανόμενη πρόσβαση στο αντικείμενο. Η επαναλαμβανόμενη πρόσβαση αντικειμένων δημιουργεί πιο επαναλαμβανόμενο κώδικα, απαιτεί περισσότερη ανάγνωση και δημιουργεί περισσότερες ευκαιρίες για λάθη. Η αποδόμηση αντικειμένων παρέχει επίσης μια ενιαία τοποθεσία ορισμού της δομής αντικειμένου που χρησιμοποιείται στο μπλοκ, αντί να απαιτεί την ανάγνωση ολόκληρου του μπλοκ για να προσδιοριστεί τι χρησιμοποιείται.

    // κακό
    function getFullName(user) {
      const firstName = user.firstName;
      const lastName = user.lastName;
    
      return `${firstName} ${lastName}`;
    }
    
    // καλό
    function getFullName(user) {
      const { firstName, lastName } = user;
      return `${firstName} ${lastName}`;
    }
    
    // άριστο
    function getFullName({ firstName, lastName }) {
      return `${firstName} ${lastName}`;
    }

  • 5.2 Χρησιμοποιήστε την αποδόμηση πινάκων (array destructuring). eslint: prefer-destructuring

    const arr = [1, 2, 3, 4];
    
    // κακό
    const first = arr[0];
    const second = arr[1];
    
    // καλό
    const [first, second] = arr;

  • 5.3 Χρησιμοποιήστε την αποδόμηση αντικειμένων για πολλαπλές τιμές επιστροφής, όχι την αποδόμηση πίνακα.

    Γιατί; Μπορείτε να προσθέσετε νέες ιδιότητες με την πάροδο του χρόνου ή να αλλάξετε τη σειρά τους χωρίς να διακόπτετε τα σημεία κλήσης.

    // κακό
    function processInput(input) {
      // then a miracle occurs
      return [left, right, top, bottom];
    }
    
    // ο καλών πρέπει να σκεφτεί τη σειρά επιστροφής των δεδομένων
    const [left, __, top] = processInput(input);
    
    // καλό
    function processInput(input) {
      // then a miracle occurs
      return { left, right, top, bottom };
    }
    
    // ο καλών επιλέγει μόνο τα δεδομένα που χρειάζεται
    const { left, top } = processInput(input);

⬆ Πίσω στην κορυφή

Συμβολοσειρές (Strings)

  • 6.1 Χρησιμοποιήστε μονά εισαγωγικά (single quotes) '' για συμβολοσειρές. eslint: quotes

    // κακό
    const name = "Capt. Janeway";
    
    // κακό - τα κυριολεκτικά πρότυπα (template literals) πρέπει να περιλαμβάνουν παρεμβολή (interpolation) ή νέες γραμμές
    const name = `Capt. Janeway`;
    
    // καλό
    const name = 'Capt. Janeway';

  • 6.2 Οι συμβολοσειρές που προκαλούν τη γραμμή να υπερβαίνει τους 100 χαρακτήρες δεν πρέπει να γράφονται σε πολλές γραμμές χρησιμοποιώντας συνένωση συμβολοσειρών (string concatenation).

    Γιατί; Οι σπασμένες συμβολοσειρές είναι επώδυνες να δουλέψετε και κάνουν τον κώδικα λιγότερο αναζητήσιμο.

    // κακό
    const errorMessage = 'This is a super long error that was thrown because \
    of Batman. When you stop to think about how Batman had anything to do \
    with this, you would get nowhere \
    fast.';
    
    // κακό
    const errorMessage = 'This is a super long error that was thrown because ' +
      'of Batman. When you stop to think about how Batman had anything to do ' +
      'with this, you would get nowhere fast.';
    
    // καλό
    const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';

  • 6.3 Κατά τη δημιουργία συμβολοσειρών μέσω προγραμματισμού, χρησιμοποιήστε συμβολοσειρές πρότυπα (template strings) αντί για συνένωση. eslint: prefer-template template-curly-spacing

    Γιατί; Οι συμβολοσειρές προτύπων σάς δίνουν μια ευανάγνωστη, συνοπτική σύνταξη με κατάλληλες νέες γραμμές και χαρακτηριστικά παρεμβολής συμβολοσειρών.

    // κακό
    function sayHi(name) {
      return 'How are you, ' + name + '?';
    }
    
    // κακό
    function sayHi(name) {
      return ['How are you, ', name, '?'].join();
    }
    
    // κακό
    function sayHi(name) {
      return `How are you, ${ name }?`;
    }
    
    // καλό
    function sayHi(name) {
      return `How are you, ${name}?`;
    }

  • 6.4 Ποτέ μη χρησιμοποιήστε τη μέθοδο eval() σε μια συμβολοσειρά, ανοίγει ευάλωτα σημεία. eslint: no-eval

  • 6.5 Μην ξεφεύγετε (escape, ) άσκοπα χαρακτήρες σε συμβολοσειρές. eslint: no-useless-escape

    Γιατί; Οι ανάστροφες κάθετες βλάπτουν την αναγνωσιμότητα, επομένως θα πρέπει να υπάρχουν μόνο όταν είναι απαραίτητο.

    // κακό
    const foo = '\'this\' \i\s \"quoted\"';
    
    // καλό
    const foo = '\'this\' is "quoted"';
    const foo = `my name is '${name}'`;

⬆ back to top

Συναρτήσεις (Functions)

  • 7.1 Χρησιμοποιήστε ονομασμένες εκφράσεις συναρτήσεων αντί για δηλώσεις συναρτήσεων. eslint: func-style

    Γιατί; Οι δηλώσεις συναρτήσεων ανυψώνονται, πράγμα που σημαίνει ότι είναι εύκολο - πολύ εύκολο - να αναφερθεί η συνάρτηση πριν οριστεί στο αρχείο. Αυτό βλάπτει την αναγνωσιμότητα και τη συντήρηση. Εάν διαπιστώσετε ότι ο ορισμός μιας συνάρτησης είναι αρκετά μεγάλος ή πολύπλοκος ώστε να παρεμποδίζει την κατανόηση του υπόλοιπου αρχείου, τότε ίσως ήρθε η ώρα να την εξαγάγετε στη δική της ενότητα! Μην ξεχάσετε να ονομάσετε ρητά την έκφραση, ανεξάρτητα από το αν το όνομα προκύπτει ή όχι από τη μεταβλητή που περιέχει (κάτι που συμβαίνει συχνά στα σύγχρονα προγράμματα περιήγησης ή όταν χρησιμοποιείτε μεταγλωττιστές όπως το Babel). Αυτό εξαλείφει τυχόν υποθέσεις σχετικά με τη στοίβα κλήσεων του σφάλματος (error call stack). (Discussion)

    // κακό
    function foo() {
      // ...
    }
    
    // κακό
    const foo = function () {
      // ...
    };
    
    // καλό
    // λεξιλογικό όνομα που ξεχωρίζει από τις επικλήσεις που αναφέρονται στη μεταβλητή
    const short = function longUniqueMoreDescriptiveLexicalFoo() {
      // ...
    };

  • 7.2 Αναδιπλώστε αμέσως τις επικαλούμενες εκφράσεις συνάρτησης σε παρένθεση. eslint: wrap-iife

    Γιατί; Μια έκφραση συνάρτησης που καλείται αμέσως (immediately invoked function expression, IIFE) είναι μια ενιαία μονάδα - η αναδίπλωση τόσο αυτής όσο και των παρενθετικών κλήσεων σε παρενθέσεις, το εκφράζει καθαρά. Σημειώστε ότι σε έναν κόσμο με ενότητες παντού, σχεδόν ποτέ δεν χρειάζεστε μια έκφραση IIFE.

    // immediately-invoked function expression (IIFE)
    (function () {
      console.log('Welcome to the Internet. Please follow me.');
    }());

  • 7.3 Ποτέ μην δηλώνετε μια συνάρτηση σε μπλοκ που δεν αρμόζει για συναρτήσεις (if, while, etc). Αντιστοιχίστε τη συνάρτηση σε μια μεταβλητή. Τα προγράμματα περιήγησης θα σας επιτρέψουν να το κάνετε, αλλά όλοι το ερμηνεύουν διαφορετικά, κάτι που είναι άσχημα νέα. eslint: no-loop-func

  • 7.4 Σημείωση: Η ECMA-262 καθορίζει το block ως κατάλογος δηλώσεων. Ένας καθορισμός συνάρτησης δεν είναι δήλωση.

    // bad
    if (currentUser) {
      function test() {
        console.log('Nope.');
      }
    }
    
    // good
    let test;
    if (currentUser) {
      test = () => {
        console.log('Yup.');
      };
    }

  • 7.5 Ποτέ μην ονομάζετε μια παράμετρο arguments. Αυτή θα έχει προτεραιότητα έναντι του αντικειμένου arguments που δίνεται σε κάθε εύρος συνάρτησης.

    // κακό
    function foo(name, options, arguments) {
      // ...
    }
    
    // καλό
    function foo(name, options, args) {
      // ...
    }

  • 7.6 Ποτέ μη χρησιμοποιείτε το arguments, αλλάξτε στη σύνταξη rest ... αντ' αυτού. eslint: prefer-rest-params

    Γιατί; Η μέθοδος ... είναι ξεκάθαρη σχετικά με τα επιχειρήματα που θέλετε να τραβήξετε. Επιπλέον, τα επιχειρήματα rest είναι ένας πραγματικός πίνακας, και όχι σαν το arguments.

    // κακό
    function concatenateAll() {
      const args = Array.prototype.slice.call(arguments);
      return args.join('');
    }
    
    // καλό
    function concatenateAll(...args) {
      return args.join('');
    }

  • 7.7 Χρησιμοποιήστε προεπιλεγμένη σύνταξη παραμέτρων αντί για μεταβολή επιχειρημάτων συνάρτησης.

    // πολύ κακό
    function handleThings(opts) {
      // Όχι! Δε θα έπρεπε να μεταβάλλουμε επιχειρήματα της συνάρτησης.
      // Δεύτερο αρνητικό: εάν το opts είναι ψευδές, θα οριστεί σε ένα αντικείμενο που μπορεί
      // να είναι αυτό που θέλετε, αλλά μπορεί να εισάγει διακριτικά σφάλματα.
      opts = opts || {};
      // ...
    }
    
    // ακόμα κακό
    function handleThings(opts) {
      if (opts === void 0) {
        opts = {};
      }
      // ...
    }
    
    // καλό
    function handleThings(opts = {}) {
      // ...
    }

  • 7.8 Αποφύγετε επιπρόσθετα γεγονότα με τις προεπιλεγμένες παραμέτρους.

    Γιατί; Είναι δύσκολες στη λογική.

    let b = 1;
    // κακό
    function count(a = b++) {
      console.log(a);
    }
    count();  // 1
    count();  // 2
    count(3); // 3
    count();  // 3

  • 7.9 Πάντα να τοποθετείτε τις προεπιλεγμένες παραμέτρους τελευταίες. eslint: default-param-last

    // κακό
    function handleThings(opts = {}, name) {
      // ...
    }
    
    // καλό
    function handleThings(name, opts = {}) {
      // ...
    }

  • 7.10 Ποτέ μην χρησιμοποιείτε τον κατασκευαστή συνάρτησης για να δημιουργήσετε μια νέα συνάρτηση. eslint: no-new-func

    Γιατί; Η δημιουργία μιας συνάρτησης με αυτόν τον τρόπο αξιολογεί μια συμβολοσειρά παρόμοια με τη μέθοδο eval(), η οποία οδηγεί σε ευάλωτα σημεία.

    // κακό
    const add = new Function('a', 'b', 'return a + b');
    
    // ακόμα κακό
    const subtract = Function('a', 'b', 'return a - b');

  • 7.11 Βάζετε διάστημα σε μια υπογραφή συνάρτησης. eslint: space-before-function-paren space-before-blocks

    Γιατί; Η συνέπεια είναι καλή και δεν χρειάζεται να προσθέσετε ή να αφαιρέσετε ένα κενό κατά την προσθήκη ή την αφαίρεση ενός ονόματος.

    // κακό
    const f = function(){};
    const g = function (){};
    const h = function() {};
    
    // καλό
    const x = function () {};
    const y = function a() {};

  • 7.12 Μην αλλάζετε ποτέ παραμέτρους. eslint: no-param-reassign

    Γιατί; Ο χειρισμός αντικειμένων που μεταβιβάζονται ως παράμετροι μπορεί να προκαλέσει ανεπιθύμητες παρενέργειες μεταβλητών στον αρχικό καλούντα.

    // κακό
    function f1(obj) {
      obj.key = 1;
    }
    
    // καλό
    function f2(obj) {
      const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1;
    }

  • 7.13 Ποτέ Μην εκχωρείτε ξανά παραμέτρους. eslint: no-param-reassign

    Γιατί; Η εκ νέου αντιστοίχιση παραμέτρων μπορεί να οδηγήσει σε απροσδόκητη συμπεριφορά, ειδικά κατά την πρόσβαση στο αντικείμενο arguments. Μπορεί επίσης να προκαλέσει προβλήματα βελτιστοποίησης, ειδικά στη μηχανή V8.

    // κακό
    function f1(a) {
      a = 1;
      // ...
    }
    
    function f2(a) {
      if (!a) { a = 1; }
      // ...
    }
    
    // καλό
    function f3(a) {
      const b = a || 1;
      // ...
    }
    
    function f4(a = 1) {
      // ...
    }

  • 7.14 Προτιμήστε τη χρήση της σύνταξης spread ... για να καλέσετε μεταβλητές συναρτήσεις. eslint: prefer-spread

    Γιατί; Είναι πιο καθαρό, δεν χρειάζεται να παρέχετε ένα πλαίσιο και δεν μπορείτε εύκολα να συνθέσετε new με apply.

    // κακό
    const x = [1, 2, 3, 4, 5];
    console.log.apply(console, x);
    
    // καλό
    const x = [1, 2, 3, 4, 5];
    console.log(...x);
    
    // κακό
    new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));
    
    // καλό
    new Date(...[2016, 8, 5]);

  • 7.15 Οι συναρτήσεις με υπογραφές ή επικλήσεις πολλαπλών γραμμών, θα πρέπει να έχουν εσοχές όπως κάθε άλλη λίστα πολλών γραμμών σε αυτόν τον οδηγό: με κάθε στοιχείο σε μια γραμμή από μόνο του, με κόμμα στο τέλος του τελευταίου στοιχείου. eslint: function-paren-newline

    // κακό
    function foo(bar,
                 baz,
                 quux) {
      // ...
    }
    
    // καλό
    function foo(
      bar,
      baz,
      quux,
    ) {
      // ...
    }
    
    // κακό
    console.log(foo,
      bar,
      baz);
    
    // καλό
    console.log(
      foo,
      bar,
      baz,
    );

⬆ Πίσω στην κορυφή

Συναρτήσεις Βέλους (Arrow Functions)

  • 8.1 Όταν πρέπει να χρησιμοποιήσετε μια ανώνυμη συνάρτηση (όπως όταν μεταβιβάζετε μια ενσωματωμένη επανάκληση), χρησιμοποιήστε σημειογραφία συνάρτησης βέλους (arrow function notation). eslint: prefer-arrow-callback, arrow-spacing

    Γιατί; Δημιουργεί μια έκδοση της συνάρτησης που εκτελείται στο πλαίσιο της λέξης this, που είναι συνήθως αυτό που θέλετε, και είναι μια πιο συνοπτική σύνταξη.

    Γιατί όχι? Εάν έχετε μια αρκετά περίπλοκη συνάρτηση, μπορείτε να μετακινήσετε αυτή τη λογική στη δική της έκφραση συνάρτησης με το όνομα.

    // κακό
    [1, 2, 3].map(function (x) {
      const y = x + 1;
      return x * y;
    });
    
    // καλό
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });

  • 8.2 Αν το σώμα της συνάρτησης αποτελείται από μία μόνο πρόταση που επιστρέφει μια έκφραση χωρίς επιπρόσθετα γεγονότα, παραλείψτε τα άγκιστρα και χρησιμοποιήστε την υπονοούμενη επιστροφή (implicit return). Διαφορετικά, κρατήστε τα άγκιστρα και χρησιμοποιήστε μια δήλωση return. eslint: arrow-parens, arrow-body-style

    Γιατί; Συντακτική ζάχαρη. Διαβάζεται καλά όταν πολλές συναρτήσεις συνδέονται μεταξύ τους.

    // κακό
    [1, 2, 3].map((number) => {
      const nextNumber = number + 1;
      `A string containing the ${nextNumber}.`;
    });
    
    // καλό
    [1, 2, 3].map((number) => `A string containing the ${number + 1}.`);
    
    // καλό
    [1, 2, 3].map((number) => {
      const nextNumber = number + 1;
      return `A string containing the ${nextNumber}.`;
    });
    
    // καλό
    [1, 2, 3].map((number, index) => ({
      [index]: number,
    }));
    
    // Καμία σιωπηρή επιστροφή με επιπρόσθετα γεγονότα
    function foo(callback) {
      const val = callback();
      if (val === true) {
        // Κάνε κάτι εάν το callback επιστρέψει true
      }
    }
    
    let bool = false;
    
    // κακό
    foo(() => bool = true);
    
    // καλό
    foo(() => {
      bool = true;
    });

  • 8.3 Σε περίπτωση που η έκφραση εκτείνεται σε πολλές γραμμές, βάλτε την σε παρένθεση για καλύτερη αναγνωσιμότητα.

    Γιατί; Δείχνει ξεκάθαρα πού ξεκινά και πού τελειώνει η λειτουργία.

    // κακό
    ['get', 'post', 'put'].map((httpMethod) => Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod,
      )
    );
    
    // καλό
    ['get', 'post', 'put'].map((httpMethod) => (
      Object.prototype.hasOwnProperty.call(
        httpMagicObjectWithAVeryLongName,
        httpMethod,
      )
    ));

  • 8.4 Να περιλαμβάνετε πάντα παρενθέσεις στα επιχειρήματα για σαφήνεια και συνέπεια. eslint: arrow-parens

    Γιατί; Ελαχιστοποιεί την ανατροπή της διαφοράς κατά την προσθήκη ή την αφαίρεση ορισμάτων.

    // κακό
    [1, 2, 3].map(x => x * x);
    
    // καλό
    [1, 2, 3].map((x) => x * x);
    
    // κακό
    [1, 2, 3].map(number => (
      `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
    ));
    
    // καλό
    [1, 2, 3].map((number) => (
      `A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!`
    ));
    
    // κακό
    [1, 2, 3].map(x => {
      const y = x + 1;
      return x * y;
    });
    
    // καλό
    [1, 2, 3].map((x) => {
      const y = x + 1;
      return x * y;
    });

  • 8.5 Αποφύγετε να μπερδεύετε τη σύνταξη συναρτήσεων βέλους (=>) με τους τελεστές σύγκρισης (<=, >=). eslint: no-confusing-arrow

    // κακό
    const itemHeight = (item) => item.height <= 256 ? item.largeSize : item.smallSize;
    
    // κακό
    const itemHeight = (item) => item.height >= 256 ? item.largeSize : item.smallSize;
    
    // καλό
    const itemHeight = (item) => (item.height <= 256 ? item.largeSize : item.smallSize);
    
    // καλό
    const itemHeight = (item) => {
      const { height, largeSize, smallSize } = item;
      return height <= 256 ? largeSize : smallSize;
    };

  • 8.6 Επιβάλλετε τη θέση των σωμάτων συναρτήσεων βέλους με υπονοούμενες επιστροφές. eslint: implicit-arrow-linebreak

    // κακό
    (foo) =>
      bar;
    
    (foo) =>
      (bar);
    
    // καλό
    (foo) => bar;
    (foo) => (bar);
    (foo) => (
       bar
    )

⬆ Πίσω στην κορυφή

Κλάσεις & Κατασκευαστές (Classes & Constructors)

  • 9.1 Πάντα να χρησιμοποιείτε τη σύνταξη με class. Αποφύγετε να χειρίζεστε το prototype αμέσως.

    Γιατί; Η σύνταξη με class είναι πιο συνοπτική και ευκολότερη στη κατανόηση της λογικής.

    // κακό
    function Queue(contents = []) {
      this.queue = [...contents];
    }
    Queue.prototype.pop = function () {
      const value = this.queue[0];
      this.queue.splice(0, 1);
      return value;
    };
    
    // καλό
    class Queue {
      constructor(contents = []) {
        this.queue = [...contents];
      }
      pop() {
        const value = this.queue[0];
        this.queue.splice(0, 1);
        return value;
      }
    }

  • 9.2 Χρησιμοποιήστε τη μέθοδο extends για κληρονόμηση.

    Γιατί; Είναι ένας ενσωματωμένος τρόπος για να κληρονομήσετε τη λειτουργικότητα του πρωτοτύπου χωρίς να διαβάλλετε τη μέθοδο instanceof του πρωτοτύπου.

    // κακό
    const inherits = require('inherits');
    function PeekableQueue(contents) {
      Queue.apply(this, contents);
    }
    inherits(PeekableQueue, Queue);
    PeekableQueue.prototype.peek = function () {
      return this.queue[0];
    };
    
    // καλό
    class PeekableQueue extends Queue {
      peek() {
        return this.queue[0];
      }
    }

  • 9.3 Οι μέθοδοι μπορούν να επιστρέψουν το this για να βοηθήσουν με την αλυσίδωση των μεθόδων.

    // κακό
    Jedi.prototype.jump = function () {
      this.jumping = true;
      return true;
    };
    
    Jedi.prototype.setHeight = function (height) {
      this.height = height;
    };
    
    const luke = new Jedi();
    luke.jump(); // => true
    luke.setHeight(20); // => undefined
    
    // καλό
    class Jedi {
      jump() {
        this.jumping = true;
        return this;
      }
    
      setHeight(height) {
        this.height = height;
        return this;
      }
    }
    
    const luke = new Jedi();
    
    luke.jump()
      .setHeight(20);

  • 9.4 Είναι εντάξει να γράψετε μια εξατομικευμένη μέθοδο toString(), απλά επιβεβαιώστε ότι δουλεύει επιτυχώς και δεν προκαλεί παρενέργειες.

    class Jedi {
      constructor(options = {}) {
        this.name = options.name || 'no name';
      }
    
      getName() {
        return this.name;
      }
    
      toString() {
        return `Jedi - ${this.getName()}`;
      }
    }

  • 9.5 Οι κλάσεις έχουν προεπιλεγμένο κατασκευαστή αν κανείς δεν καθοριστεί. Μια άδεια συνάρτηση κατασκευαστή ή μια που απλά κατευθύνει σε μια κλάση γονέα είναι περιττή. eslint: no-useless-constructor

    // κακό
    class Jedi {
      constructor() {}
    
      getName() {
        return this.name;
      }
    }
    
    // κακό
    class Rey extends Jedi {
      constructor(...args) {
        super(...args);
      }
    }
    
    // καλό
    class Rey extends Jedi {
      constructor(...args) {
        super(...args);
        this.name = 'Rey';
      }
    }

  • 9.6 Αποφύγετε να αντιγράψετε εις διπλούν τα μέλη μιας κλάσης. eslint: no-dupe-class-members

    Γιατί; Οι δηλώσεις αντιγράφων μελών της κλάσης θα προτιμήσουν σιωπηλά το τελευταίο - το να έχετε αντίγραφα είναι βέβαια ένα θέμα.

    // κακό
    class Foo {
      bar() { return 1; }
      bar() { return 2; }
    }
    
    // καλό
    class Foo {
      bar() { return 1; }
    }
    
    // καλό
    class Foo {
      bar() { return 2; }
    }

  • 9.7 Οι μέθοδοι κλάσης πρέπει να χρησιμοποιούν τη λέξη this ή να μετατραπούν σε στατικές μεθόδος, εκτός εάν μια εξωτερική βιβλιοθήκη ή ένα framework απαιτεί τη χρήση συγκεκριμένων μη στατικών μεθόδων. Το να υπάρχει μια μέθοδος θα πρέπει να υποδεικνύει ότι συμπεριφέρεται διαφορετικά με βάση τις ιδιότητες του δέκτη. eslint: class-methods-use-this

    // κακό
    class Foo {
      bar() {
        console.log('bar');
      }
    }
    
    // καλό - χρησιμοποιείται
    class Foo {
      bar() {
        console.log(this.bar);
      }
    }
    
    // καλό - εξαιρείται ο κατασκευαστής
    class Foo {
      constructor() {
        // ...
      }
    }
    
    // καλό - οι στατικές μεθόδους δεν αναμένεται να χρησιμοποιήσουν αυτό
    class Foo {
      static bar() {
        console.log('bar');
      }
    }

⬆ Πίσω στην κορυφή

Ενότητες (Modules)

  • 10.1 Πάντα χρησιμοποιείτε ενότητες (import/export) πάνω από ένα μη τυπικό σύστημα μονάδων. Μπορείτε πάντα να κάνετε μεταγραφή στο προτιμώμενο σύστημα μονάδων.

    Γιατί; Οι ενότητες είναι το μέλλον, ας αρχίσουμε να χρησιμοποιούμε το μέλλον τώρα.

    // κακό
    const AirbnbStyleGuide = require('./AirbnbStyleGuide');
    module.exports = AirbnbStyleGuide.es6;
    
    // εντάξει
    import AirbnbStyleGuide from './AirbnbStyleGuide';
    export default AirbnbStyleGuide.es6;
    
    // άριστο
    import { es6 } from './AirbnbStyleGuide';
    export default es6;

  • 10.2 Μη χρησιμοποιείτε εισαγωγές wildcard (*).

    Γιατί; Αυτό διασφαλίζει ότι έχετε μια προεπιλεγμένη εξαγωγή.

    // κακό
    import * as AirbnbStyleGuide from './AirbnbStyleGuide';
    
    // καλό
    import AirbnbStyleGuide from './AirbnbStyleGuide';

  • 10.3 Και μην εξάγετε απευθείας από εισαγωγή.

    Γιατί; Αν και το μονόγραμμο είναι συνοπτικό, η ύπαρξη ενός σαφούς τρόπου εισαγωγής και ενός σαφούς τρόπου εξαγωγής κάνει τα πράγματα συνεπή.

    // κακό
    // filename es6.js
    export { es6 as default } from './AirbnbStyleGuide';
    
    // καλό
    // filename es6.js
    import { es6 } from './AirbnbStyleGuide';
    export default es6;

  • 10.4 Εισαγωγή μόνο από μια διαδρομή (path) σε ένα μέρος. eslint: no-duplicate-imports

    Γιατί; Η ύπαρξη πολλών γραμμών που εισάγουν από την ίδια διαδρομή μπορεί να κάνει πιο δύσκολη τη συντήρηση του κώδικα.

    // κακό
    import foo from 'foo';
    // … some other imports … //
    import { named1, named2 } from 'foo';
    
    // καλό
    import foo, { named1, named2 } from 'foo';
    
    // καλό
    import foo, {
      named1,
      named2,
    } from 'foo';

  • 10.5 Μην εξάγετε μεταβλητές συνδέσεις. eslint: import/no-mutable-exports

    Γιατί; Η μετάλλαξη θα πρέπει να αποφεύγεται γενικά, αλλά ειδικότερα κατά την εξαγωγή μεταλλάσιμων δεσμών. Ενώ αυτή η τεχνική μπορεί να χρειαστεί για ορισμένες ειδικές περιπτώσεις, γενικά, μόνο σταθερές αναφορές θα πρέπει να εξάγονται.

    // κακό
    let foo = 3;
    export { foo };
    
    // καλό
    const foo = 3;
    export { foo };

  • 10.6 Σε ενότητες με μία εξαγωγή, προτιμήστε την προεπιλεγμένη εξαγωγή από την εξαγωγή με όνομα. eslint: import/prefer-default-export

    Γιατί; Για να ενθαρρύνετε περισσότερα αρχεία που εξάγουν μόνο ένα πράγμα, το οποίο είναι καλύτερο για αναγνωσιμότητα και δυνατότητα συντήρησης.

    // κακό
    export function foo() {}
    
    // καλό
    export default function foo() {}

  • 10.7 Βάλτε όλες τις δηλώσεις import πάνω από τις μη-εισαγωγικές δηλώσεις. eslint: import/first

    Γιατί; Εφόσον οι εισαγωγές ανυψώνονται, κρατώντας τις όλες στην κορυφή αποτρέπει απρόσμενη συμπεριφορά.

    // κακό
    import foo from 'foo';
    foo.init();
    
    import bar from 'bar';
    
    // καλό
    import foo from 'foo';
    import bar from 'bar';
    
    foo.init();

  • 10.8 Οι εισαγωγές πολλαπλών γραμμών θα πρέπει να έχουν εσοχές όπως ακριβώς και τα κυριολεκτικά αντικειμένων και πινάκων πολλαπλών γραμμών. eslint: object-curly-newline

    Γιατί; Τα άγκιστρα ακολουθούν τους ίδιους κανόνες εσοχής με κάθε άλλο μπλοκ αγκίστρων στον αισθητικό οδηγό όπως και τα κόμματα που ακολουθούν.

    // κακό
    import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
    
    // καλό
    import {
      longNameA,
      longNameB,
      longNameC,
      longNameD,
      longNameE,
    } from 'path';

  • 10.9 Απαγορεύστε τη σύνταξη φόρτωσης του Webpack (Webpack loader syntax) στις δηλώσεις εισαγωγής ενοτήτων. eslint: import/no-webpack-loader-syntax

    Γιατί; Δεδομένου ότι η χρήση της σύνταξης Webpack στις εισαγωγές συνδέει τον κώδικα σε μια δέσμη ενοτήτων. Προτιμήστε να χρησιμοποιήσετε τη σύνταξη φόρτωσης στο webpack.config.js.

    // κακό
    import fooSass from 'css!sass!foo.scss';
    import barCss from 'style!css!bar.css';
    
    // καλό
    import fooSass from 'foo.scss';
    import barCss from 'bar.css';

  • 10.10 Μην συμπεριλάβετε επεκτάσεις ονόματος αρχείων JavaScript. eslint: import/extensions

    Γιατί; Η συμπερίληψη επεκτάσεων εμποδίζει την ανακατασκευή (refactoring) και κωδικοποιεί ακατάλληλα τις λεπτομέρειες εφαρμογής της ενότητας που εισάγετε σε κάθε καταναλωτή.

    // κακό
    import foo from './foo.js';
    import bar from './bar.jsx';
    import baz from './baz/index.jsx';
    
    // καλό
    import foo from './foo';
    import bar from './bar';
    import baz from './baz';

⬆ Πίσω στην κορυφή

Επαναλήπτες & Γενικευτές (Iterators & Generators)

  • 11.1 Μην χρησιμοποιείτε επαναλήπτες. Προτιμήστε τις συναρτήσεις υψηλότερης τάξης της JavaScript αντί για βρόχους (loops) όπως for-in or for-of. eslint: no-iterator no-restricted-syntax

    Γιατί; Αυτό επιβάλλει τον αμετάβλητο κανόνα μας. Η ενασχόληση με καθαρές συναρτήσεις που επιστρέφουν τιμές (pure functions) είναι ευκολότερο να αιτιολογηθεί από τις παρενέργειες των δομών επανάληψης.

    Χρησιμοποιήστε τις μεθόδους map() / every() / filter() / find() / findIndex() / reduce() / some() / ... για επανάληψη σε πίνακες, και τις μεθόδους Object.keys() / Object.values() / Object.entries() για να παράγετε πίνακες ώστε να μπορείτε να κάνετε επανάληψη πάνω σε αντικείμενα.

    const numbers = [1, 2, 3, 4, 5];
    
    // bad
    let sum = 0;
    for (let num of numbers) {
      sum += num;
    }
    sum === 15;
    
    // good
    let sum = 0;
    numbers.forEach((num) => {
      sum += num;
    });
    sum === 15;
    
    // best (use the functional force)
    const sum = numbers.reduce((total, num) => total + num, 0);
    sum === 15;
    
    // bad
    const increasedByOne = [];
    for (let i = 0; i < numbers.length; i++) {
      increasedByOne.push(numbers[i] + 1);
    }
    
    // good
    const increasedByOne = [];
    numbers.forEach((num) => {
      increasedByOne.push(num + 1);
    });
    
    // best (keeping it functional)
    const increasedByOne = numbers.map((num) => num + 1);

  • 11.2 Μη χρησιμοποιείτε γενικευτές προς το παρόν.

    Γιατί; Δεν μεταγράφονται καλά στην ES5.

  • 11.3 Αν πρέπει να χρησιμοποιήσετε γενικευτές, ή αν δεν εκτιμάτε τη συμβουλή μας, βεβαιωθείτε ότι η υπογραφή της λειτουργίας τους έχει τοποθετηθεί σωστά. eslint: generator-star-spacing

    Γιατί; Οι λέξεις function και * αποτελούν μέρος της ίδιας εννοιολογικής λέξης - το μεν * δεν είναι τροποποιητής για το function, το δε function* είναι μια μοναδική κατασκευή, διαφορετική από function.

    // κακό
    function * foo() {
      // ...
    }
    
    // κακό
    const bar = function * () {
      // ...
    };
    
    // κακό
    const baz = function *() {
      // ...
    };
    
    // κακό
    const quux = function*() {
      // ...
    };
    
    // κακό
    function*foo() {
      // ...
    }
    
    // κακό
    function *foo() {
      // ...
    }
    
    // πολύ κακό
    function
    *
    foo() {
      // ...
    }
    
    // πολύ κακό
    const wat = function
    *
    () {
      // ...
    };
    
    // καλό
    function* foo() {
      // ...
    }
    
    // καλό
    const foo = function* () {
      // ...
    };

⬆ Πίσω στην κορυφή

Ιδιότητες (Properties)

  • 12.1 Χρησιμοποιήστε σημειογραφία με τελείες (dot notation) κατά την πρόσβαση σε ιδιότητες. eslint: dot-notation

    const luke = {
      jedi: true,
      age: 28,
    };
    
    // κακό
    const isJedi = luke['jedi'];
    
    // καλό
    const isJedi = luke.jedi;

  • 12.2 Χρησιμοποιήστε σημειογραφία παρένθεσης [] κατά την πρόσβαση σε ιδιότητες με μεταβλητές.

    const luke = {
      jedi: true,
      age: 28,
    };
    
    function getProp(prop) {
      return luke[prop];
    }
    
    const isJedi = getProp('jedi');

  • 12.3 Χρησιμοποιήστε τον τελεστή εκθέσεως ** κατά τον υπολογισμό των εκπτώσεων. eslint: no-restricted-properties.

    // κακό
    const binary = Math.pow(2, 10);
    
    // καλό
    const binary = 2 ** 10;

⬆ Πίσω στην κορυφή

Μεταβλητές (Variables)

  • 13.1 Πάντα να χρησιμοποιείτε const ή let για διακήρυξη μεταβλητών. Αν δεν το κάνετε αυτό θα έχετε καθολικές μεταβλητές (global variables). Θέλουμε να αποφύγουμε τη μόλυνση του παγκόσμιου χώρου ονομάτων (global namespace). Ο Captain Planet μας προειδοποίησε για αυτό. eslint: no-undef prefer-const

    // κακό
    superPower = new SuperPower();
    
    // καλό
    const superPower = new SuperPower();

  • 13.2 Χρησιμοποιήστε μια δήλωση const ή let ανά μεταβλητή ή ανάθεση. eslint: one-var

    Γιατί; Είναι πιο εύκολο να προσθέσετε νέες δηλώσεις μεταβλητών με αυτόν τον τρόπο και δεν χρειάζεται ποτέ να ανησυχείτε για την αντικατάσταση ενός ; με ένα , ή την εισαγωγή διαφορών μόνο με σημεία στίξης. Μπορείτε επίσης να προχωρήσετε σε κάθε δήλωση με το πρόγραμμα εντοπισμού σφαλμάτων (debugger), αντί να τις περάσετε όλες ταυτόχρονα.

    // κακό
    const items = getItems(),
        goSportsTeam = true,
        dragonball = 'z';
    
    // κακό
    // (συγκρίνετε με πάνω, και προσπαθήστε να εντοπίσετε το λάθος)
    const items = getItems(),
        goSportsTeam = true;
        dragonball = 'z';
    
    // καλό
    const items = getItems();
    const goSportsTeam = true;
    const dragonball = 'z';

  • 13.3 Ομαδοποιήστε πρώτα τις δηλώσεις const και μετά τις δηλώσεις let.

    Γιατί; Αυτό είναι χρήσιμο όταν αργότερα ίσως χρειαστεί να αντιστοιχίσετε μια μεταβλητή ανάλογα με μία από τις προηγουμένως εκχωρημένες μεταβλητές.

    // κακό
    let i, len, dragonball,
        items = getItems(),
        goSportsTeam = true;
    
    // κακό
    let i;
    const items = getItems();
    let dragonball;
    const goSportsTeam = true;
    let len;
    
    // καλό
    const goSportsTeam = true;
    const items = getItems();
    let dragonball;
    let i;
    let length;

  • 13.4 Αντιστοιχίστε μεταβλητές όπου τις χρειάζεστε, αλλά τοποθετήστε τις σε λογικό μέρος.

    Γιατί; Οι λέξεις let και constέχουν εύρος μπλοκ και όχι συνάρτησης.

    // κακό - περιττή κλήση συνάρτησης
    function checkName(hasName) {
      const name = getName();
    
      if (hasName === 'test') {
        return false;
      }
    
      if (name === 'test') {
        this.setName('');
        return false;
      }
    
      return name;
    }
    
    // καλό
    function checkName(hasName) {
      if (hasName === 'test') {
        return false;
      }
    
      const name = getName();
    
      if (name === 'test') {
        this.setName('');
        return false;
      }
    
      return name;
    }

  • 13.5 Μην αλυσιδώνετε αναθέσεις μεταβλητών. eslint: no-multi-assign

    Γιατί; Η αλυσίδα των αναθέσεων μεταβλητών δημιουργεί υπονοούμενες καθολικές μεταβλητές.

    // κακό
    (function example() {
      // Η JavaScript ερμηνεύει αυτό ως
      // let a = ( b = ( c = 1 ) );
      // Η λέξη let εφαρμόζεται μόνο στη μεταβλητή a; οι μεταβλητές b και c γίνονται
      // καθολικές μεταβλητές.
      let a = b = c = 1;
    }());
    
    console.log(a); // δίνει ReferenceError
    console.log(b); // 1
    console.log(c); // 1
    
    // good
    (function example() {
      let a = 1;
      let b = a;
      let c = a;
    }());
    
    console.log(a); // δίνει ReferenceError
    console.log(b); // δίνει ReferenceError
    console.log(c); // δίνει ReferenceError
    
    // το ίδιο ισχύει για τη λέξη `const`

  • 13.6 Αποφύγετε τη χρήση μεμονωμένων αυξήσεων και μειώσεων (++, --). eslint no-plusplus

    Γιατί; Σύμφωνα με την τεκμηρίωση του eslint, οι δηλώσεις μοναδιαίας αύξησης και μείωσης υπόκεινται σε αυτόματη εισαγωγή ερωτηματικών και μπορεί να προκαλέσουν υπονοούμενα σφάλματα με αυξανόμενες ή φθίνουσες τιμές εντός μιας εφαρμογής. Είναι επίσης πιο εκφραστικό να μεταλλάσσετε τις αξίες σας με δηλώσεις όπως num += 1 αντί για num++ ή num ++. Η απαγόρευση των μονομερών δηλώσεων αύξησης και μείωσης σας εμποδίζει επίσης να αυξήσετε ή να μειώσετε τιμές εκ των προτέρων ακούσια, γεγονός που μπορεί επίσης να προκαλέσει απροσδόκητη συμπεριφορά στα προγράμματά σας.

    // κακό
    
    const array = [1, 2, 3];
    let num = 1;
    num++;
    --num;
    
    let sum = 0;
    let truthyCount = 0;
    for (let i = 0; i < array.length; i++) {
      let value = array[i];
      sum += value;
      if (value) {
        truthyCount++;
      }
    }
    
    // καλό
    
    const array = [1, 2, 3];
    let num = 1;
    num += 1;
    num -= 1;
    
    const sum = array.reduce((a, b) => a + b, 0);
    const truthyCount = array.filter(Boolean).length;

  • 13.7 Αποφύγετε τις αλλαγές γραμμής πριν ή μετά = σε μια εκχώρηση. Εάν η εκχώρησή σας παραβιάζει το max-len, περικυκλώστε την αξία σε παρενθέσεις. eslint operator-linebreak.

    Γιατί; Διακοπές γραμμής γύρω από το = μπορεί να αλλοιώσουν την αξία μιας ανάθεσης.

    // κακό
    const foo =
      superLongLongLongLongLongLongLongLongFunctionName();
    
    // κακό
    const foo
      = 'superLongLongLongLongLongLongLongLongString';
    
    // καλό
    const foo = (
      superLongLongLongLongLongLongLongLongFunctionName()
    );
    
    // καλό
    const foo = 'superLongLongLongLongLongLongLongLongString';

  • 13.8 Απαγορεύστε τις μη χρησιμοποιημένες μεταβλητές. eslint: no-unused-vars

    Γιατί; Οι μεταβλητές που δηλώνονται και δεν χρησιμοποιούνται πουθενά στον κώδικα είναι πιθανότατα ένα σφάλμα λόγω ατελούς ανακατασκευής. Τέτοιες μεταβλητές καταλαμβάνουν χώρο στον κώδικα και μπορεί να οδηγήσουν σε σύγχυση από τους αναγνώστες.

    // κακό
    
    const some_unused_var = 42;
    
    // Οι εγγεγραμμένες μόνο μεταβλητές δεν θεωρούνται ως χρησιμοποιούμενες.
    let y = 10;
    y = 5;
    
    // Μια ανάγνωση για μια τροποποίηση από μόνη της δεν θεωρείται ότι χρησιμοποιείται.
    let z = 0;
    z = z + 1;
    
    // Μη χρησιμοποιημένα επιχειρήματα συνάρτησης
    function getX(x, y) {
        return x;
    }
    
    // καλό
    
    function getXPlusY(x, y) {
      return x + y;
    }
    
    const x = 1;
    const y = a + 2;
    
    alert(getXPlusY(x, y));
    
    // 'type' αγνοείται ακόμη και αν δεν χρησιμοποιείται γιατί έχει αδερφή ιδιότητα rest.
    // Αυτή είναι μια μορφή εξαγωγής ενός αντικειμένου που παραλείπει τα καθορισμένα κλειδιά.
    const { type, ...coords } = data;
    // Το 'coords' είναι τώρα το αντικείμενο 'data' χωρίς την ιδιότητα 'type'.

⬆ Πίσω στην κορυφή

Ανύψωση (Hoisting)

  • 14.1 Οι δηλώσεις var ανυψώνονται στην κορυφή του πλησιέστερου εύρους συναρτήσεων περικλείοντάς τους, η εκχώρηση τους όχι. Οι δηλώσεις const και let αποκτούν νέα διάσταση με μια νέα έννοια που ονομάζεται Temporal Dead Zones (TDZ). Είναι σημαντικό να ξέρετε γιατί το typeof δεν είναι πλέον ασφαλές.

    // ξέρουμε ότι αυτό δε θα δούλευε (υποθέτωντας ότι
    // δεν υπάρχει καθολική μεταβλητή notDefined)
    function example() {
      console.log(notDefined); // => δίνει ReferenceError
    }
    
    // δημιουργώντας διακήρυξη μεταβλητής αφού
    // αναφέρετε τη μεταβλητή θα δουλέψει λόγω της
    // ανύψωσης μεταβλητής. Σημείωση: η αξία 
    // εκχώρησης του `true` δεν ανυψώνεται.
    function example() {
      console.log(declaredButNotAssigned); // => undefined
      var declaredButNotAssigned = true;
    }
    
    // ο διερμηνευτής ανυψώνει τη διακήρυξη
    // στην κορυφή του πεδίου εφαρμογής,
    // που σημαίνει ότι το παράδειγμά μας θα μπορούσε να ξαναγραφεί ως:
    function example() {
      let declaredButNotAssigned;
      console.log(declaredButNotAssigned); // => undefined
      declaredButNotAssigned = true;
    }
    
    // χρησιμοποιώντας const και let
    function example() {
      console.log(declaredButNotAssigned); // => δίνει ReferenceError
      console.log(typeof declaredButNotAssigned); // => δίνει ReferenceError
      const declaredButNotAssigned = true;
    }

  • 14.2 Οι ανώνυμες εκφράσεις συνάρτησης ανεβάζουν το όνομα της μεταβλητής τους, αλλά όχι την εκχώρηση συνάρτησης.

    function example() {
      console.log(anonymous); // => undefined
    
      anonymous(); // => TypeError anonymous is not a function
    
      var anonymous = function () {
        console.log('anonymous function expression');
      };
    }

  • 14.3 Οι εκφράσεις με όνομα συνάρτησης ανυψώνουν το όνομα της μεταβλητής, όχι το όνομα της συνάρτησης ή το σώμα της συνάρτησης.

    function example() {
      console.log(named); // => undefined
    
      named(); // => TypeError named is not a function
    
      superPower(); // => ReferenceError superPower is not defined
    
      var named = function superPower() {
        console.log('Flying');
      };
    }
    
    // το ίδιο ισχύει όταν το όνομα της συνάρτησης
    // είναι το ίδιο με το όνομα της μεταβλητής.
    function example() {
      console.log(named); // => undefined
    
      named(); // => TypeError named is not a function
    
      var named = function named() {
        console.log('named');
      };
    }

  • 14.4 Οι δηλώσεις συναρτήσεων ανυψώνουν το όνομά τους και το σώμα λειτουργίας.

    function example() {
      superPower(); // => Flying
    
      function superPower() {
        console.log('Flying');
      }
    }
  • Για περεταίρω πληροφορίες ανατρέξτε στο JavaScript Scoping & Hoisting του Ben Cherry.

⬆ Πίσω στην κορυφή

Τελεστές Σύγκρισης & Ισότητα (Comparison Operators & Equality)

  • 15.1 Χρησιμοποιήστε τα === και !== αντί για == και !=. eslint: eqeqeq

  • 15.2 Δομές ελέγχου όπως η δήλωση if αξιολογούν την έκφρασή τους χρησιμοποιώντας εξαναγκασμό με την αφηρημένη μέθοδο ToBoolean και πάντα ακολουθούν αυτούς τους απλούς κανόνες:

    • Objects θεωρείται true
    • Undefined θεωρείται false
    • Null θεωρείται false
    • Booleans θεωρείται the value of the boolean
    • Numbers θεωρείται false if +0, -0, ή NaN, ειδάλλως true
    • Strings θεωρείται false όντας άδεια συμβολοσειρά '', ειδάλλως true
    if ([0] && []) {
      // true
      // ένας πίνακας (ακόμα και άδειος) είναι αντικείμενο, τα αντικείμενα θεωρούνται true
    }

  • 15.3 Χρησιμοποιήστε συντομεύσεις για booleans, αλλά ρητές συγκρίσεις για συμβολοσειρές και αριθμούς.

    // κακό
    if (isValid === true) {
      // ...
    }
    
    // καλό
    if (isValid) {
      // ...
    }
    
    // κακό
    if (name) {
      // ...
    }
    
    // καλό
    if (name !== '') {
      // ...
    }
    
    // κακό
    if (collection.length) {
      // ...
    }
    
    // καλό
    if (collection.length > 0) {
      // ...
    }

  • 15.5 Χρησιμοποιήστε άγκιστρα για κατασκευή μπλοκ στις περιπτώσεις case και default οι οποίες περιλαμβάνουν διακηρύξεις σε μορφή κειμένου (π.χ. let, const, function, και class). eslint: no-case-declarations

    Γιατί; Οι λεξικές δηλώσεις είναι ορατές σε όλο το μπλοκ switch αλλά αρχικοποιείται μόνο όταν εκχωρείται, κάτι που συμβαίνει μόνο όταν η case περίπτωση του έχει φτάσει. Αυτό προκαλεί προβλήματα όταν πολλές περιπτώσεις case προσπαθούν να καθορίσουν το ίδιο.

    // κακό
    switch (foo) {
      case 1:
        let x = 1;
        break;
      case 2:
        const y = 2;
        break;
      case 3:
        function f() {
          // ...
        }
        break;
      default:
        class C {}
    }
    
    // καλό
    switch (foo) {
      case 1: {
        let x = 1;
        break;
      }
      case 2: {
        const y = 2;
        break;
      }
      case 3: {
        function f() {
          // ...
        }
        break;
      }
      case 4:
        bar();
        break;
      default: {
        class C {}
      }
    }

  • 15.6 Τα τριμερή (ternaries) δεν πρέπει να είναι ένθετα και γενικά να είναι εκφράσεις μονής γραμμής. eslint: no-nested-ternary

    // κακό
    const foo = maybe1 > maybe2
      ? "bar"
      : value1 > value2 ? "baz" : null;
    
    // διάσπαση σε 2 χωριστές τριμερείς εκφράσεις
    const maybeNull = value1 > value2 ? 'baz' : null;
    
    // καλό
    const foo = maybe1 > maybe2
      ? 'bar'
      : maybeNull;
    
    // άριστο
    const foo = maybe1 > maybe2 ? 'bar' : maybeNull;

  • 15.7 Αποφύγετε περιττές τριμερείς δηλώσεις. eslint: no-unneeded-ternary

    // κακό
    const foo = a ? a : b;
    const bar = c ? true : false;
    const baz = c ? false : true;
    const quux = a != null ? a : b;
    
    // καλό
    const foo = a || b;
    const bar = !!c;
    const baz = !c;
    const quux = a ?? b;

  • 15.8 Όταν αναμιγνύετε τελεστές, περικλείστε τους σε παρένθεση. Η μόνη εξαίρεση είναι οι τυπικοί αριθμητικοί τελεστές: +, -, και ** δεδομένου ότι η προτεραιότητά τους είναι ευρέως κατανοητή. Συνιστούμε να περικλείσετε τους τελεστές / and * σε παρένθεση γιατί η προτεραιότητα τους μπορεί να είναι διφορούμενη όταν αναμειγνύονται. eslint: no-mixed-operators

    Γιατί; Αυτό βελτιώνει την αναγνωσιμότητα και διευκρινίζει την πρόθεση του προγραμματιστή.

    // κακό
    const foo = a && b < 0 || c > 0 || d + 1 === 0;
    
    // κακό
    const bar = a ** b - 5 % d;
    
    // κακό
    // one may be confused into thinking (a || b) && c
    if (a || b && c) {
      return d;
    }
    
    // κακό
    const bar = a + b / c * d;
    
    // καλό
    const foo = (a && b < 0) || c > 0 || (d + 1 === 0);
    
    // καλό
    const bar = a ** b - (5 % d);
    
    // καλό
    if (a || (b && c)) {
      return d;
    }
    
    // καλό
    const bar = a + (b / c) * d;

⬆ Πίσω στην κορυφή

Μπλοκ (Blocks)

  • 16.1 Χρησιμοποιήστε άγκιστρα με όλα τα μπλοκ πολλαπλών γραμμών. eslint: nonblock-statement-body-position

    // κακό
    if (test)
      return false;
    
    // καλό
    if (test) return false;
    
    // καλό
    if (test) {
      return false;
    }
    
    // κακό
    function foo() { return false; }
    
    // καλό
    function bar() {
      return false;
    }

  • 16.2 Εάν χρησιμοποιείτε if και else μπλοκ πολλαπλών γραμμών, τοποθετείστε το else στην ίδια γραμμή με το καταληκτικό άγκιστρο του μπλοκ if. eslint: brace-style

    // κακό
    if (test) {
      thing1();
      thing2();
    }
    else {
      thing3();
    }
    
    // καλό
    if (test) {
      thing1();
      thing2();
    } else {
      thing3();
    }

  • 16.3 Εάν ένα μπλοκ if συνέχεια εκτελεί μια δήλωση επιστροφής, το μπλοκ else δεν είναι απαραίτητο. Μια δήλωση return σε ένα μπλοκ else if μετά από ένα μπλοκ if που περιέχει το return μπορεί να διαχωριστεί σε πολλά μπλοκ if. eslint: no-else-return

    // κακό
    function foo() {
      if (x) {
        return x;
      } else {
        return y;
      }
    }
    
    // κακό
    function cats() {
      if (x) {
        return x;
      } else if (y) {
        return y;
      }
    }
    
    // κακό
    function dogs() {
      if (x) {
        return x;
      } else {
        if (y) {
          return y;
        }
      }
    }
    
    // καλό
    function foo() {
      if (x) {
        return x;
      }
    
      return y;
    }
    
    // καλό
    function cats() {
      if (x) {
        return x;
      }
    
      if (y) {
        return y;
      }
    }
    
    // καλό
    function dogs(x) {
      if (x) {
        if (z) {
          return y;
        }
      } else {
        return z;
      }
    }

⬆ Πίσω στην κορυφή

Δηλώσεις Ελέγχου (Control Statements)

  • 17.1 Σε περίπτωση που η δήλωση ελέγχου (if, while κ.α.) είναι πολύ μεγάλη ή υπερβαίνει το μέγιστο μήκος γραμμής, κάθε (ομαδοποιημένη) συνθήκη θα μπορούσε να τεθεί σε μια νέα γραμμή. Ο λογικός τελεστής πρέπει να ξεκινήσει τη γραμμή.

    Γιατί; Η απαίτηση τελεστών στην αρχή της γραμμής διατηρεί τους τελεστές ευθυγραμμισμένους και ακολουθεί ένα μοτίβο παρόμοιο με τη μέθοδο αλυσοποίησης. Αυτό βελτιώνει επίσης την αναγνωσιμότητα καθιστώντας ευκολότερη την οπτική παρακολούθηση σύνθετης λογικής.

    // κακό
    if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {
      thing1();
    }
    
    // κακό
    if (foo === 123 &&
      bar === 'abc') {
      thing1();
    }
    
    // κακό
    if (foo === 123
      && bar === 'abc') {
      thing1();
    }
    
    // κακό
    if (
      foo === 123 &&
      bar === 'abc'
    ) {
      thing1();
    }
    
    // καλό
    if (
      foo === 123
      && bar === 'abc'
    ) {
      thing1();
    }
    
    // καλό
    if (
      (foo === 123 || bar === 'abc')
      && doesItLookGoodWhenItBecomesThatLong()
      && isThisReallyHappening()
    ) {
      thing1();
    }
    
    // καλό
    if (foo === 123 && bar === 'abc') {
      thing1();
    }

  • 17.2 Μην χρησιμοποιείτε τελεστές επιλογής αντί για δηλώσεις ελέγχου.

    // κακό
    !isRunning && startRunning();
    
    // καλό
    if (!isRunning) {
      startRunning();
    }

⬆ Πίσω στην κορυφή

Σχόλια (Comments)

  • 18.1 Χρησιμοποιήστε /** ... */ για σχόλια πολλαπλών γραμμών.

    // κακό
    // η συνάρτηση make() επιστρέφει νέο αντικέιμενο
    // με βάση το όνομα ετικέτας που έχει περάσει
    //
    // @param {String} tag
    // @return {Element} element
    function make(tag) {
    
      // ...
    
      return element;
    }
    
    // καλό
    /**
     * η συνάρτηση make() επιστρέφει νέο αντικέιμενο
     * με βάση το όνομα ετικέτας που έχει περάσει
     */
    function make(tag) {
    
      // ...
    
      return element;
    }

  • 18.2 Χρησιμοποιήστε // για κόμματα μιας γραμμής. Τοποθετήστε τα σχόλια μιας γραμμής σε μια νέα γραμμή πάνω από το θέμα του σχολίου. Τοποθετήστε μια κενή γραμμή πριν από το σχόλιο, εκτός εάν βρίσκεται στην πρώτη γραμμή ενός μπλοκ.

    // κακό
    const active = true;  // is current tab
    
    // καλό
    // is current tab
    const active = true;
    
    // κακό
    function getType() {
      console.log('fetching type...');
      // θέσε τον προεπιλεγμένο τύπο σε 'no type'
      const type = this.type || 'no type';
    
      return type;
    }
    
    // καλό
    function getType() {
      console.log('fetching type...');
    
      // θέσε τον προεπιλεγμένο τύπο σε 'no type'
      const type = this.type || 'no type';
    
      return type;
    }
    
    // επίσης καλό
    function getType() {
      // θέσε τον προεπιλεγμένο τύπο σε 'no type'
      const type = this.type || 'no type';
    
      return type;
    }

  • 18.3 Ξεκινήστε όλα τα σχόλια με ένα κενό για να διευκολύνετε την ανάγνωση. eslint: spaced-comment

    // κακό
    //is current tab
    const active = true;
    
    // καλό
    // is current tab
    const active = true;
    
    // κακό
    /**
     * η συνάρτηση make() επιστρέφει νέο αντικέιμενο
     * με βάση το όνομα ετικέτας που έχει περάσει
     */
    function make(tag) {
    
      // ...
    
      return element;
    }
    
    // καλό
    /**
     * η συνάρτηση make() επιστρέφει νέο αντικέιμενο
     * με βάση το όνομα ετικέτας που έχει περάσει
     */
    function make(tag) {
    
      // ...
    
      return element;
    }

  • 18.4 Ξεκινώντας τα σχόλιά σας με FIXME ή TODO βοηθά άλλους προγραμματιστές να κατανοήσουν γρήγορα εάν επισημαίνετε ένα πρόβλημα που πρέπει να επανεξεταστεί ή εάν προτείνετε μια λύση στο πρόβλημα που πρέπει να εφαρμοστεί. Αυτά είναι διαφορετικά από τα κανονικά σχόλια, επειδή είναι εφαρμόσιμα. Οι ενέργειες είναι FIXME: -- need to figure this out ή TODO: -- need to implement.

  • 18.5 Χρησιμοποιήστε // FIXME: για να σχολιάσετε προβλήματα.

    class Calculator extends Abacus {
      constructor() {
        super();
    
        // FIXME: shouldn’t use a global here
        total = 0;
      }
    }

  • 18.6 Χρησιμοποιήστε // TODO: για να καταγράψετε λύσεις σε προβλήματα.

    class Calculator extends Abacus {
      constructor() {
        super();
    
        // TODO: total should be configurable by an options param
        this.total = 0;
      }
    }

⬆ Πίσω στην κορυφή

Κενός Χώρος (Whitespace)

  • 19.1 Χρησιμοποιήστε χαρακτήρες διαστήματος (soft tabs) σε 2 κενά. eslint: indent

    // κακό
    function foo() {
    ∙∙∙∙let name;
    }
    
    // κακό
    function bar() {
    ∙let name;
    }
    
    // καλό
    function baz() {
    ∙∙let name;
    }

  • 19.2 Τοποθετήστε 1 κενό πριν από το μπροστινό στήριγμα. eslint: space-before-blocks

    // κακό
    function test(){
      console.log('test');
    }
    
    // καλό
    function test() {
      console.log('test');
    }
    
    // κακό
    dog.set('attr',{
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });
    
    // καλό
    dog.set('attr', {
      age: '1 year',
      breed: 'Bernese Mountain Dog',
    });

  • 19.3 Τοποθετήστε 1 κενό πριν από την αρχική παρένθεση στις εντολές ελέγχου (if, while κ.α.). Place no space between the argument list and the function name in function calls and declarations. eslint: keyword-spacing

    // κακό
    if(isJedi) {
      fight ();
    }
    
    // καλό
    if (isJedi) {
      fight();
    }
    
    // κακό
    function fight () {
      console.log ('Swooosh!');
    }
    
    // καλό
    function fight() {
      console.log('Swooosh!');
    }

  • 19.4 Εκκινήστε τους τελεστές με κενά. eslint: space-infix-ops

    // κακό
    const x=y+5;
    
    // καλό
    const x = y + 5;

  • 19.5 Τερματίστε αρχεία με έναν χαρακτήρα νέας γραμμής. eslint: eol-last

    // κακό
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;
    // κακό
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;
    
    // καλό
    import { es6 } from './AirbnbStyleGuide';
      // ...
    export default es6;

  • 19.6 Χρησιμοποιήστε εσοχές όταν κάνετε μακριές αλυσίδες μεθόδου (περισσότερες από 2 αλυσίδες μεθόδου). Χρησιμοποιήστε μια προπορευόμενη κουκκίδα, η οποία τονίζει ότι η γραμμή είναι μια κλήση μεθόδου, όχι μια νέα πρόταση. eslint: newline-per-chained-call no-whitespace-before-property

    // κακό
    $('#items').find('.selected').highlight().end().find('.open').updateCount();
    
    // κακό
    $('#items').
      find('.selected').
        highlight().
        end().
      find('.open').
        updateCount();
    
    // καλό
    $('#items')
      .find('.selected')
        .highlight()
        .end()
      .find('.open')
        .updateCount();
    
    // κακό
    const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
        .attr('width', (radius + margin) * 2).append('svg:g')
        .attr('transform', `translate(${radius + margin}, ${radius + margin})`)
        .call(tron.led);
    
    // καλό
    const leds = stage.selectAll('.led')
        .data(data)
      .enter().append('svg:svg')
        .classed('led', true)
        .attr('width', (radius + margin) * 2)
      .append('svg:g')
        .attr('transform', `translate(${radius + margin}, ${radius + margin})`)
        .call(tron.led);
    
    // καλό
    const leds = stage.selectAll('.led').data(data);
    const svg = leds.enter().append('svg:svg');
    svg.classed('led', true).attr('width', (radius + margin) * 2);
    const g = svg.append('svg:g');
    g.attr('transform', `translate(${radius + margin}, ${radius + margin})`).call(tron.led);

  • 19.7 Αφήστε μια κενή γραμμή μετά τα μπλοκ και πριν από την επόμενη πρόταση.

    // κακό
    if (foo) {
      return bar;
    }
    return baz;
    
    // καλό
    if (foo) {
      return bar;
    }
    
    return baz;
    
    // κακό
    const obj = {
      foo() {
      },
      bar() {
      },
    };
    return obj;
    
    // καλό
    const obj = {
      foo() {
      },
    
      bar() {
      },
    };
    
    return obj;
    
    // κακό
    const arr = [
      function foo() {
      },
      function bar() {
      },
    ];
    return arr;
    
    // καλό
    const arr = [
      function foo() {
      },
    
      function bar() {
      },
    ];
    
    return arr;

  • 19.8 Μην γεμίζετε τα μπλοκ σας με κενές γραμμές. eslint: padded-blocks

    // κακό
    function bar() {
    
      console.log(foo);
    
    }
    
    // κακό
    if (baz) {
    
      console.log(quux);
    } else {
      console.log(foo);
    
    }
    
    // κακό
    class Foo {
    
      constructor(bar) {
        this.bar = bar;
      }
    }
    
    // καλό
    function bar() {
      console.log(foo);
    }
    
    // καλό
    if (baz) {
      console.log(quux);
    } else {
      console.log(foo);
    }

  • 19.9 Μην χρησιμοποιείτε πολλές κενές γραμμές για να συμπληρώσετε τον κώδικά σας. eslint: no-multiple-empty-lines

    // κακό
    class Person {
      constructor(fullName, email, birthday) {
        this.fullName = fullName;
    
    
        this.email = email;
    
    
        this.setAge(birthday);
      }
    
    
      setAge(birthday) {
        const today = new Date();
    
    
        const age = this.getAge(today, birthday);
    
    
        this.age = age;
      }
    
    
      getAge(today, birthday) {
        // ..
      }
    }
    
    // καλό
    class Person {
      constructor(fullName, email, birthday) {
        this.fullName = fullName;
        this.email = email;
        this.setAge(birthday);
      }
    
      setAge(birthday) {
        const today = new Date();
        const age = getAge(today, birthday);
        this.age = age;
      }
    
      getAge(today, birthday) {
        // ..
      }
    }

  • 19.10 Μην προσθέτετε κενά μέσα σε παρενθέσεις. eslint: space-in-parens

    // κακό
    function bar( foo ) {
      return foo;
    }
    
    // καλό
    function bar(foo) {
      return foo;
    }
    
    // κακό
    if ( foo ) {
      console.log(foo);
    }
    
    // καλό
    if (foo) {
      console.log(foo);
    }

  • 19.11 Do not add spaces inside brackets. eslint: array-bracket-spacing

    // κακό
    const foo = [ 1, 2, 3 ];
    console.log(foo[ 0 ]);
    
    // καλό
    const foo = [1, 2, 3];
    console.log(foo[0]);

  • 19.12 Προσθέστε κενά μέσα στα άγκιστρα. eslint: object-curly-spacing

    // κακό
    const foo = {clark: 'kent'};
    
    // καλό
    const foo = { clark: 'kent' };

  • 19.13 Αποφύγετε να έχετε γραμμές κώδικα που υπερβαίνουν τους 100 χαρακτήρες (συμπεριλαμβανομένων των κενών διαστημάτων). Σημείωση: όπως αναφέρεται πάνω, οι μακριές συμβολοσειρές εξαιρούνται από αυτόν τον κανόνα και δεν πρέπει να χωρίζονται. eslint: max-len

    Γιατί; Αυτό εξασφαλίζει αναγνωσιμότητα και δυνατότητα συντήρησης.

    // κακό
    const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy;
    
    // κακό
    $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.'));
    
    // καλό
    const foo = jsonData
      && jsonData.foo
      && jsonData.foo.bar
      && jsonData.foo.bar.baz
      && jsonData.foo.bar.baz.quux
      && jsonData.foo.bar.baz.quux.xyzzy;
    
    // καλύτερο
    const foo = jsonData
      ?.foo
      ?.bar
      ?.baz
      ?.quux
      ?.xyzzy;
    
    // καλό
    $.ajax({
      method: 'POST',
      url: 'https://airbnb.com/',
      data: { name: 'John' },
    })
      .done(() => console.log('Congratulations!'))
      .fail(() => console.log('You have failed this city.'));

  • 19.14 Απαιτείται σταθερή απόσταση μέσα σε ένα διακριτικό ανοιχτού μπλοκ και το επόμενο διακριτικό στην ίδια γραμμή. Αυτός ο κανόνας επιβάλλει επίσης συνεπή απόσταση μέσα σε ένα διακριτικό κλεισίματος και προηγούμενο διακριτικό στην ίδια γραμμή. eslint: block-spacing

    // κακό
    function foo() {return true;}
    if (foo) { bar = 0;}
    
    // καλό
    function foo() { return true; }
    if (foo) { bar = 0; }

  • 19.15 Αποφύγετε τα κενά πριν από τα κόμματα και απαιτήστε ένα διάστημα μετά τα κόμματα. eslint: comma-spacing

    // κακό
    const foo = 1,bar = 2;
    const arr = [1 , 2];
    
    // καλό
    const foo = 1, bar = 2;
    const arr = [1, 2];

  • 19.16 Επιβάλλετε απόσταση εντός των αγκύλων υπολογισμένων ιδιοτήτων. eslint: computed-property-spacing

    // κακό
    obj[foo ]
    obj[ 'foo']
    const x = {[ b ]: a}
    obj[foo[ bar ]]
    
    // καλό
    obj[foo]
    obj['foo']
    const x = { [b]: a }
    obj[foo[bar]]

  • 19.17 Αποφύγετε τα κενά μεταξύ των συναρτήσεων και των επικλήσεών τους. eslint: func-call-spacing

    // κακό
    func ();
    
    func
    ();
    
    // καλό
    func();

  • 19.18 Επιβάλλετε απόσταση μεταξύ κλειδιών και τιμών στις κυριολεκτικές ιδιότητες αντικειμένου. eslint: key-spacing

    // κακό
    const obj = { foo : 42 };
    const obj2 = { foo:42 };
    
    // καλό
    const obj = { foo: 42 };

  • 19.19 Αποφύγετε τα υστερούντα κενά στο τέλος των γραμμών. eslint: no-trailing-spaces

  • 19.20 Avoid multiple empty lines, only allow one newline at the end of files, and avoid a newline at the beginning of files. eslint: no-multiple-empty-lines

    // κακό - πολλές άδειες γραμμές
    const x = 1;
    
    
    const y = 2;
    
    // κακό - 2+ νέες γραμμές στο τέλος του αρχείου
    const x = 1;
    const y = 2;
    
    
    // κακό - 1+ νέες γραμμές στην αρχή του αρχείου
    
    const x = 1;
    const y = 2;
    
    // καλό
    const x = 1;
    const y = 2;

⬆ Πίσω στην κορυφή

Κόμματα (Commas)

  • 20.1 Προπορευόμενα κόμματα: Όχι. eslint: comma-style

    // κακό
    const story = [
        once
      , upon
      , aTime
    ];
    
    // καλό
    const story = [
      once,
      upon,
      aTime,
    ];
    
    // κακό
    const hero = {
        firstName: 'Ada'
      , lastName: 'Lovelace'
      , birthYear: 1815
      , superPower: 'computers'
    };
    
    // good
    const hero = {
      firstName: 'Ada',
      lastName: 'Lovelace',
      birthYear: 1815,
      superPower: 'computers',
    };

  • 20.2 Επιπρόσθετο υπολειπόμενο κόμμα: Ναι. eslint: comma-dangle

    Γιατί; Αυτό οδηγεί σε καθαρότερες εντολές git diff. Επίσης, transpilers όπως το Babel θα αφαιρέσουν το πρόσθετο κόμμα μετάδοσης στον μεταφρασμένο κώδικα, πράγμα που σημαίνει ότι δεν χρειάζεται να ανησυχείτε για το πρόβλημα του υπολειπόμενου κόμματος σε προγράμματα περιήγησης παλαιού τύπου.

    // κακό - git diff χωρίς υπολειπόμενο κόμμα
    const hero = {
         firstName: 'Florence',
    -    lastName: 'Nightingale'
    +    lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing']
    };
    
    // καλό - git diff με υπολειπόμενο κόμμα
    const hero = {
         firstName: 'Florence',
         lastName: 'Nightingale',
    +    inventorOf: ['coxcomb chart', 'modern nursing'],
    };
    // κακό
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully'
    };
    
    const heroes = [
      'Batman',
      'Superman'
    ];
    
    // καλό
    const hero = {
      firstName: 'Dana',
      lastName: 'Scully',
    };
    
    const heroes = [
      'Batman',
      'Superman',
    ];
    
    // κακό
    function createHero(
      firstName,
      lastName,
      inventorOf
    ) {
      // does nothing
    }
    
    // καλό
    function createHero(
      firstName,
      lastName,
      inventorOf,
    ) {
      // does nothing
    }
    
    // καλό (λάβετε υπόψιν ότι ένα κόμμα δε πρέπει να εμφανίζεται μετά από μια παράμετρο rest)
    function createHero(
      firstName,
      lastName,
      inventorOf,
      ...heroArgs
    ) {
      // δεν κάνει τίποτα
    }
    
    // κακό
    createHero(
      firstName,
      lastName,
      inventorOf
    );
    
    // καλό
    createHero(
      firstName,
      lastName,
      inventorOf,
    );
    
    // καλό (λάβετε υπόψιν ότι ένα κόμμα δε πρέπει να εμφανίζεται μετά από μια παράμετρο rest)
    createHero(
      firstName,
      lastName,
      inventorOf,
      ...heroArgs
    );

⬆ Πίσω στην κορυφή

Ερωτηματικά (Semicolons)

  • 21.1 Ναι. eslint: semi

    Γιατί; Όταν η JavaScript συναντά μια αλλαγή γραμμής χωρίς ερωτηματικό, χρησιμοποιεί ένα σύνολο κανόνων που ονομάζεται Αυτόματη εισαγωγή ερωτηματικών για να προσδιορίσει εάν θα πρέπει να θεωρήσει αυτή τη διακοπή γραμμής ως το τέλος μιας δήλωσης και (όπως υποδηλώνει το όνομα) να τοποθετήσει ένα ερωτηματικό στο κωδικός πριν από τη διακοπή της γραμμής, αν το πιστεύει. Ωστόσο, το ASI περιέχει μερικές εκκεντρικές συμπεριφορές και ο κώδικάς σας θα σπάσει εάν η JavaScript παρερμηνεύσει την αλλαγή γραμμής σας. Αυτοί οι κανόνες θα γίνουν πιο περίπλοκοι καθώς οι νέες δυνατότητες γίνονται μέρος της JavaScript. Ο ρητός τερματισμός των δηλώσεών σας και η ρύθμιση παραμέτρων του λιναριού σας ώστε να συλλέγει ερωτηματικά που λείπουν θα σας βοηθήσει να μην αντιμετωπίσετε προβλήματα.

    // κακό - εγείρει εξαίρεση
    const luke = {}
    const leia = {}
    [luke, leia].forEach((jedi) => jedi.father = 'vader')
    
    // κακό - εγείρει εξαίρεση
    const reaction = "No! That’s impossible!"
    (async function meanwhileOnTheFalcon() {
      // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
      // ...
    }())
    
    // κακό - επιστρέφει "undefined" αντί για την τιμή στην επόμενη γραμμή - συμβαίνει πάντα όταν η "return" βρίσκεται σε μια γραμμή από μόνη της λόγω ASI!
    function foo() {
      return
        'search your feelings, you know it to be foo'
    }
    
    // καλό
    const luke = {};
    const leia = {};
    [luke, leia].forEach((jedi) => {
      jedi.father = 'vader';
    });
    
    // καλό
    const reaction = 'No! That’s impossible!';
    (async function meanwhileOnTheFalcon() {
      // handle `leia`, `lando`, `chewie`, `r2`, `c3p0`
      // ...
    }());
    
    // καλό
    function foo() {
      return 'search your feelings, you know it to be foo';
    }

    Read more.

⬆ Πίσω στην κορυφή

Casting Τύπων & Εξαναγκασμός (Type Casting & Coercion)

  • 22.1 Εκτελέστε εξαναγκασμό τύπου στην αρχή της δήλωσης.

  • 22.2 Συμβολσειρές: eslint: no-new-wrappers

    // => this.reviewScore = 9;
    
    // κακό
    const totalScore = new String(this.reviewScore); // ο τύπος totalScore είναι "object" όχι "string"
    
    // κακό
    const totalScore = this.reviewScore + ''; // καλεί το this.reviewScore.valueOf()
    
    // κακό
    const totalScore = this.reviewScore.toString(); // δεν είναι εγγυημένο ότι θα επιστρέψει string
    
    // καλό
    const totalScore = String(this.reviewScore);

  • 22.3 Αριθμοί: Χρησιμοποιήστε το Number για casting τύπου και το parseInt πάντα με μια ρίζα για την ανάλυση συμβολοσειρών. eslint: radix no-new-wrappers

    Γιατί; Η συνάρτηση parseInt παράγει μια ακέραια τιμή που υπαγορεύεται από την ερμηνεία των περιεχομένων του ορίσματος συμβολοσειράς σύμφωνα με την καθορισμένη ρίζα. Το κύριο κενό διάστημα στη συμβολοσειρά αγνοείται. Εάν η ρίζα είναι undefined ή 0, θεωρείται ότι είναι 10, εκτός από την περίπτωση που ο αριθμός ξεκινά με τα ζεύγη χαρακτήρων 0x ή 0X, οπότε θεωρείται η ρίζα 16. Αυτό διαφέρει από το ECMAScript 3, το οποίο απλώς αποθάρρυνε (αλλά επέτρεπε) την οκταδική ερμηνεία. Πολλές υλοποιήσεις δεν έχουν υιοθετήσει αυτήν τη συμπεριφορά από το 2013. Και, επειδή πρέπει να υποστηρίζονται παλαιότερα προγράμματα περιήγησης, να προσδιορίζετε πάντα μια βάση.

    const inputValue = '4';
    
    // κακό
    const val = new Number(inputValue);
    
    // κακό
    const val = +inputValue;
    
    // κακό
    const val = inputValue >> 0;
    
    // κακό
    const val = parseInt(inputValue);
    
    // καλό
    const val = Number(inputValue);
    
    // καλό
    const val = parseInt(inputValue, 10);

  • 22.4 Εάν για οποιονδήποτε λόγο κάνετε κάτι άγριο και το parseInt είναι το σημείο συμφόρησής σας και πρέπει να χρησιμοποιήσετε το Bitshift για λόγους απόδοσης, αφήστε ένα σχόλιο εξηγώντας γιατί και τι κάνετε.

    // καλό
    /**
     * parseInt was the reason my code was slow.
     * Bitshifting the String to coerce it to a
     * Number made it a lot faster.
     */
    const val = inputValue >> 0;

  • 22.5 Σημείωση: Να είστε προσεκτικοί όταν χρησιμοποιείτε λειτουργίες bitshift. Οι αριθμοί αντιπροσωπεύονται ως τιμές 64-bit, αλλά οι λειτουργίες bitshift επιστρέφουν πάντα έναν ακέραιο αριθμό 32-bit (πηγή). Το bitshift μπορεί να οδηγήσει σε απροσδόκητη συμπεριφορά για ακέραιες τιμές μεγαλύτερες από 32 bit. Συζητήστε. Ο μεγαλύτερος υπογεγραμμένος ακέραιος 32-bit είναι 2,147,483,647:

    2147483647 >> 0; // => 2147483647
    2147483648 >> 0; // => -2147483648
    2147483649 >> 0; // => -2147483647

  • 22.6 Booleans: eslint: no-new-wrappers

    const age = 0;
    
    // κακό
    const hasAge = new Boolean(age);
    
    // καλό
    const hasAge = Boolean(age);
    
    // best
    const hasAge = !!age;

⬆ Πίσω στην κορυφή

Συμβάσεις Ονομασίας (Naming Conventions)

  • 23.1 Αποφύγετε τα ονόματα με ένα γράμμα. Να είστε περιγραφικοί με την ονομασία σας. eslint: id-length

    // κακό
    function q() {
      // ...
    }
    
    // καλό
    function query() {
      // ...
    }

  • 23.2 Χρησιμοποιήστε camelCase όταν ονομάζετε αντικείμενα, συναρτήσεις και παρουσίες. eslint: camelcase

    // κακό
    const OBJEcttsssss = {};
    const this_is_my_object = {};
    function c() {}
    
    // καλό
    const thisIsMyObject = {};
    function thisIsMyFunction() {}

  • 23.3 Χρησιμοποιήστε PascalCase μόνο όταν ονομάζετε κατασκευαστές ή κλάσεις. eslint: new-cap

    // κακό
    function user(options) {
      this.name = options.name;
    }
    
    const bad = new user({
      name: 'nope',
    });
    
    // καλό
    class User {
      constructor(options) {
        this.name = options.name;
      }
    }
    
    const good = new User({
      name: 'yup',
    });

  • 23.4 Μη χρησιμοποιείτε υστερούντες ή προπορευόμενες υπογράμμιση. eslint: no-underscore-dangle

    Γιατί; Η JavaScript δεν έχει την έννοια του απορρήτου όσον αφορά τις ιδιότητες ή τις μεθόδους. Αν και η κύρια υπογράμμιση είναι μια κοινή σύμβαση που σημαίνει “ιδιωτικό”, στην πραγματικότητα, αυτές οι ιδιότητες είναι πλήρως δημόσιες και ως εκ τούτου αποτελούν μέρος της δημόσιας σύμβασης API σας. Αυτή η σύμβαση μπορεί να οδηγήσει τους προγραμματιστές να πιστεύουν λανθασμένα ότι μια αλλαγή δεν θα λογαριάσει ως παραβίαση ή ότι δεν χρειάζονται δοκιμές. tl;dr: εάν θέλετε κάτι να είναι “ιδιωτικό”, δεν πρέπει να είναι εμφανώς παρόν.

    // κακό
    this.__firstName__ = 'Panda';
    this.firstName_ = 'Panda';
    this._firstName = 'Panda';
    
    // καλό
    this.firstName = 'Panda';
    
    // καλό, in environments where WeakMaps are available
    // see https://kangax.github.io/compat-table/es6/#test-WeakMap
    const firstNames = new WeakMap();
    firstNames.set(this, 'Panda');

  • 23.5 Μην αποθηκεύετε αναφορές στη λέξη this. Χρησιμοποιήστε συναρτήσεις βέλους ή Function#bind.

    // κακό
    function foo() {
      const self = this;
      return function () {
        console.log(self);
      };
    }
    
    // κακό
    function foo() {
      const that = this;
      return function () {
        console.log(that);
      };
    }
    
    // καλό
    function foo() {
      return () => {
        console.log(this);
      };
    }

  • 23.6 Ένα όνομα αρχείου βάσης πρέπει να ταιριάζει ακριβώς με το όνομα της προεπιλεγμένης εξαγωγής του.

    // περιεχόμενα αρχείου 1
    class CheckBox {
      // ...
    }
    export default CheckBox;
    
    // περιεχόμενα αρχείου 2
    export default function fortyTwo() { return 42; }
    
    // περιεχόμενα αρχείου 3
    export default function insideDirectory() {}
    
    // σε άλλον φάκελο
    // κακό
    import CheckBox from './checkBox'; // PascalCase import/export, camelCase filename
    import FortyTwo from './FortyTwo'; // PascalCase import/filename, camelCase export
    import InsideDirectory from './InsideDirectory'; // PascalCase import/filename, camelCase export
    
    // κακό
    import CheckBox from './check_box'; // PascalCase import/export, snake_case filename
    import forty_two from './forty_two'; // snake_case import/filename, camelCase export
    import inside_directory from './inside_directory'; // snake_case import, camelCase export
    import index from './inside_directory/index'; // requiring the index file explicitly
    import insideDirectory from './insideDirectory/index'; // requiring the index file explicitly
    
    // καλό
    import CheckBox from './CheckBox'; // PascalCase export/import/filename
    import fortyTwo from './fortyTwo'; // camelCase export/import/filename
    import insideDirectory from './insideDirectory'; // camelCase export/import/directory name/implicit "index"
    // ^ υποστηρίζει και το insideDirectory.js και το insideDirectory/index.js

  • 23.7 Χρησιμοποιήστε camelCase κατά την εξαγωγή-προεπιλογή μιας συνάρτησης. Το όνομα του αρχείου σας πρέπει να είναι πανομοιότυπο με το όνομα της συνάρτησής σας.

    function makeStyleGuide() {
      // ...
    }
    
    export default makeStyleGuide;

  • 23.8 Χρησιμοποιήστε PascalCase όταν εξάγετε έναν κατασκευαστή / κλάση / singleton / βιβλιοθήκη συναρτήσεων / άδειο αντικείμενο.

    const AirbnbStyleGuide = {
      es6: {
      },
    };
    
    export default AirbnbStyleGuide;

  • 23.9 Τα ακρωνύμια και οι αρχικισμοί πρέπει πάντα να είναι όλα κεφαλαία ή όλα πεζά.

    Γιατί; Τα ονόματα είναι για αναγνωσιμότητα, όχι για να κατευνάσουν έναν αλγόριθμο υπολογιστή.

    // bad
    import SmsContainer from './containers/SmsContainer';
    
    // bad
    const HttpRequests = [
      // ...
    ];
    
    // good
    import SMSContainer from './containers/SMSContainer';
    
    // good
    const HTTPRequests = [
      // ...
    ];
    
    // also good
    const httpRequests = [
      // ...
    ];
    
    // best
    import TextMessageContainer from './containers/TextMessageContainer';
    
    // best
    const requests = [
      // ...
    ];

  • 23.10 Μπορείτε προαιρετικά να γράψετε κεφαλαία μια σταθερά μόνο εάν (1) εξαχθεί, (2) είναι const (δεν μπορεί να ανατεθεί ξανά) και (3) ο προγραμματιστής μπορεί να εμπιστευτεί αυτό (και οι ένθετες ιδιότητές του) να μην αλλάξουν ποτέ.

    Γιατί; Αυτό είναι ένα πρόσθετο εργαλείο για να βοηθήσει σε καταστάσεις όπου ο προγραμματιστής δεν είναι σίγουρος εάν μια μεταβλητή μπορεί να αλλάξει ποτέ. Οι UPPERCASE_VARIABLES ενημερώνουν τον προγραμματιστή ότι μπορεί να εμπιστευτεί τη μεταβλητή (και τις ιδιότητές της) να μην αλλάξει.

    • Τι γίνεται με όλες τις μεταβλητές const; - Αυτό δεν είναι απαραίτητο, επομένως δεν πρέπει να χρησιμοποιείται κεφαλαία για σταθερές σε ένα αρχείο. Ωστόσο, θα πρέπει να χρησιμοποιείται για εξαγόμενες σταθερές.
    • Τι γίνεται με τα εξαγόμενα αντικείμενα; - Κεφαλαία γράμματα στο ανώτερο επίπεδο εξαγωγής (π.χ. EXPORTED_OBJECT.key) και διατηρήστε ότι όλες οι ένθετες ιδιότητες δεν αλλάζουν.
    // κακό
    const PRIVATE_VARIABLE = 'should not be unnecessarily uppercased within a file';
    
    // κακό
    export const THING_TO_BE_CHANGED = 'should obviously not be uppercased';
    
    // κακό
    export let REASSIGNABLE_VARIABLE = 'do not use let with uppercase variables';
    
    // ---
    
    // επιτρέπεται αλλά δεν παρέχει σημασιολογική (semantic) αξία
    export const apiKey = 'SOMEKEY';
    
    // καλύτερο στις περισσότερες περιπτώσεις
    export const API_KEY = 'SOMEKEY';
    
    // ---
    
    // κακό - άσκοπα κεφαλαία γράμματα χωρίς να προσθέτει καμία σημασιολογική αξία
    export const MAPPING = {
      KEY: 'value'
    };
    
    // καλό
    export const MAPPING = {
      key: 'value',
    };

⬆ Πίσω στην κορυφή

Στοιχεία Πρόσβασης (Accessors)

  • 24.1 Δεν απαιτούνται συναρτήσεις πρόσβασης για ιδιότητες.

  • 24.2 Μην χρησιμοποιείτε τους getters/setters JavaScript, καθώς προκαλούν απροσδόκητες παρενέργειες και είναι πιο δύσκολο να δοκιμαστούν, να διατηρηθούν και να αιτιολογηθούν. Αντίθετα, εάν κάνετε συναρτήσεις πρόσβασης, χρησιμοποιήστε τα getVal() και setVal('hello').

    // κακό
    class Dragon {
      get age() {
        // ...
      }
    
      set age(value) {
        // ...
      }
    }
    
    // καλό
    class Dragon {
      getAge() {
        // ...
      }
    
      setAge(value) {
        // ...
      }
    }

  • 24.3 Εάν η ιδιότητα/μέθοδος είναι boolean, χρησιμοποιήστε isVal() ή hasVal().

    // κακό
    if (!dragon.age()) {
      return false;
    }
    
    // καλό
    if (!dragon.hasAge()) {
      return false;
    }

  • 24.4 Είναι εντάξει να δημιουργείτε συναρτήσεις get() και set(), αλλά να είστε συνεπείς.

    class Jedi {
      constructor(options = {}) {
        const lightsaber = options.lightsaber || 'blue';
        this.set('lightsaber', lightsaber);
      }
    
      set(key, val) {
        this[key] = val;
      }
    
      get(key) {
        return this[key];
      }
    }

⬆ Πίσω στην κορυφή

Γεγονότα (Events)

  • 25.1 Όταν επισυνάπτετε ωφέλιμα φορτία δεδομένων (data payload) σε γεγονότα (είτε γεγονότα DOM είτε κάτι πιο αποκλειστικό όπως γεγονότα Backbone), μεταβιβάστε ένα κυριολεκτικό αντικείμενο (γνωστό και ως "hash") αντί για μια μη επεξεργασμένη τιμή. Αυτό επιτρέπει σε έναν επόμενο συνεισφέροντα να προσθέσει περισσότερα δεδομένα στο ωφέλιμο φορτίο συμβάντος χωρίς να βρει και να ενημερώσει κάθε χειριστή για το γεγονός. Για παράδειγμα, αντί για:

    // κακό
    $(this).trigger('listingUpdated', listing.id);
    
    // ...
    
    $(this).on('listingUpdated', (e, listingID) => {
      // do something with listingID
    });

    προτιμήστε:

    // καλό
    $(this).trigger('listingUpdated', { listingID: listing.id });
    
    // ...
    
    $(this).on('listingUpdated', (e, data) => {
      // do something with data.listingID
    });

⬆ Πίσω στην κορυφή

jQuery

  • 26.1 Βάλτε πρόθεμα σε μεταβλητών αντικειμένου jQuery με $.

    // κακό
    const sidebar = $('.sidebar');
    
    // καλό
    const $sidebar = $('.sidebar');
    
    // καλό
    const $sidebarBtn = $('.sidebar-btn');

  • 26.2 Πλαισιώστε σε μνήμη cache τις αναζητήσεις (lookups) jQuery.

    // κακό
    function setSidebar() {
      $('.sidebar').hide();
    
      // ...
    
      $('.sidebar').css({
        'background-color': 'pink',
      });
    }
    
    // καλό
    function setSidebar() {
      const $sidebar = $('.sidebar');
      $sidebar.hide();
    
      // ...
    
      $sidebar.css({
        'background-color': 'pink',
      });
    }

  • 26.3 Για DOM queries χρησιμοποιήστε Cascading $('.sidebar ul') ή parent > child $('.sidebar > ul'). jsPerf

  • 26.4 Use find with queries αντικειμένων jQuery με εύρος.

    // κακό
    $('ul', '.sidebar').hide();
    
    // κακό
    $('.sidebar').find('ul').hide();
    
    // καλό
    $('.sidebar ul').hide();
    
    // καλό
    $('.sidebar > ul').hide();
    
    // καλό
    $sidebar.find('ul').hide();

⬆ Πίσω στην κορυφή

Συμβατότητα ECMAScript 5

⬆ Πίσω στην κορυφή

Στυλ ECMAScript 6+ (ES 2015+)

  • 28.1 Αυτή είναι μια συλλογή συνδέσμων στα διάφορα χαρακτηριστικά της ES6+.
  1. Συναρτήσεις Βέλους (Arrow Functions)
  2. Κλάσεις & Κατασκευαστές (Classes & Constructors)
  3. Συντομογραφία Αντικειμένου (Object Shorthand)
  4. Σύνοψη Αντικειμένου (Object Concise)
  5. Υπολογισμένες Ιδιότητες Αντικειμένου (Object Computed Properties)
  6. Συμβολοσειρές Πρότυπα (Template Strings)
  7. Αποδόμηση (Destructuring)
  8. Προεπιλεγμένες Παράμετροι (Default Parameters)
  9. Σύνταξη Rest (Rest Syntax)
  10. Σύνταξη Spread Πινάκων (Array Spreads)
  11. Let και Const
  12. Τελεστής Εκθέσεως (Exponentiation Operator)
  13. Επαναλήπτες & Γενικευτές (Iterators & Generators)
  14. Ενότητες (Modules)

⬆ Πίσω στην κορυφή

Τυπική Βιβλιοθήκη (Standard Library)

Η Τυπική Βιβλιοθήκη περιέχει βοηθητικά προγράμματα που είναι λειτουργικά κατεστραμμένα αλλά παραμένουν για λόγους παλαιού τύπου.

  • 29.1 Χρησιμοποιήστε το Number.isNaN αντί για το καθολικό isNaN. eslint: no-restricted-globals

    Γιατί; Το καθολικό isNaN εξαναγκάζει τους μη αριθμούς σε αριθμούς, επιστρέφοντας true για οτιδήποτε εξαναγκάζει σε NaN. Εάν αυτή η συμπεριφορά είναι επιθυμητή, κάντε τη σαφή.

    // κακό
    isNaN('1.2'); // false
    isNaN('1.2.3'); // true
    
    // καλό
    Number.isNaN('1.2.3'); // false
    Number.isNaN(Number('1.2.3')); // true

  • 29.2 Χρησιμοποιήστε το Number.isFinite αντί για το καθολικό isFinite. eslint: no-restricted-globals

    Why? Το καθολικό isFinite επιστρέφοντας true για οτιδήποτε εξαναγκάζει σε έναν πεπερασμένο αριθμό. Εάν αυτή η συμπεριφορά είναι επιθυμητή, κάντε τη σαφή.

    // κακό
    isFinite('2e3'); // true
    
    // καλό
    Number.isFinite('2e3'); // false
    Number.isFinite(parseInt('2e3', 10)); // true

⬆ Πίσω στην κορυφή

Δοκιμές (Testing)

  • 30.1 Ναι.

    function foo() {
      return true;
    }

  • 30.2 Όχι, αλλά σοβαρά:
    • Όποιο πλαίσιο δοκιμών (testing framework) χρησιμοποιείτε, θα πρέπει να γράφετε δοκιμές!
    • Προσπαθήστε να γράψετε πολλές μικρές καθαρές συναρτήσεις και ελαχιστοποιήστε τα σημεία όπου συμβαίνουν μεταλλάξεις.
    • Να είστε προσεκτικοί με τα μέρη των δοκιμών (stubs) και τις προσομοιώσεις τους (mocks) - μπορεί να κάνουν τις δοκιμές σας πιο ευάλωτες.
    • Χρησιμοποιούμε κυρίως mocha και jest στην Airbnb. Το tape χρησιμοποιείται επιπλέον ενίοτε σε μικρές, χωριστές ενότητες.
    • Η κάλυψη δοκιμών 100% είναι ένας ικανός στόχος που πρέπει να επιδιώξετε, ακόμα κι αν δεν είναι πάντα πρακτικό να τον πετύχετε.
    • Κάθε φορά που διορθώνετε ένα σφάλμα, γράψτε μια δοκιμή παλινδρόμησης (regression test). Ένα σφάλμα που διορθώθηκε χωρίς δοκιμή παλινδρόμησης είναι σχεδόν βέβαιο ότι θα σπάσει ξανά στο μέλλον.

⬆ Πίσω στην κορυφή

Απόδοση (Performance)

⬆ back to top

Πηγές

Μαθαίνοντας ES6+

Διαβάστε Αυτό

Εργαλεία

Άλλοι Αισθητικοί Οδηγοί

Άλλα Στυλ

Περαιτέρω Διάβασμα

Βιβλία

Blogs

Podcasts

⬆ Πίσω στην κορυφή

Στα Άγρια

Αυτή είναι μια λίστα οργανισμών που χρησιμοποιούν αυτόν τον αισθητικό οδηγό. Στείλτε μας ένα αίτημα (pull request) και θα σας προσθέσουμε στη λίστα.

⬆ Πίσω στην κορυφή

Μετάφραση

Ο αισθητικός οδηγός είναι επίσης διαθέσιμος και σε άλλες γλώσσες:

Ο Οδηγός του Αισθητικού Οδηγού της JavaScript

Συνομιλήστε Μαζί Μας Σχετικά Με Τη JavaScript

  • Βρείτε μας στο gitter.

Συνεισφέροντες

Άδεια

(The MIT License)

Copyright (c) 2012 Airbnb

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

⬆ Πίσω στην κορυφή

Τροπολογίες

We encourage you to fork this guide and change the rules to fit your team’s style guide. Below, you may list some amendments to the style guide. This allows you to periodically update your style guide without having to deal with merge conflicts.

};