Home

Awesome

Original Repository: airbnb/javascript

Airbnb JavaScript Style Guide() {

Разумен подход за писане на JavaScript

<a name='TOC'>Съдържанине</a>

  1. Типове
  2. Обекти
  3. Масиви
  4. Низове
  5. Функции
  6. Полета
  7. Променливи
  8. Деклариране и използване на променливи
  9. Условни изрази и равенства
  10. Блокове
  11. Коментари
  12. Празни полета
  13. Запетаи
  14. Точка и запетая
  15. Преобразуване на типове
  16. Наименуване практики
  17. Достъпване
  18. Конструктори
  19. Събития
  20. Модули
  21. jQuery
  22. ES5 Съвместимост
  23. Тестване
  24. Изпъление
  25. Ресурси
  26. Къде се използват тези практики
  27. Превод
  28. JavaScript стилов пътеводител
  29. Сътрудници
  30. Лиценз

<a name='types'>Типове</a>

<a name='objects'>Обекти</a>

<a name='arrays'>Масиви</a>

<a name='strings'>Низове</a>

<a name='functions'>Функции</a>

<a name='properties'>Полета</a>

<a name='variables'>Променливи</a>

<a name='hoisting'>Деклариране и използване на променливи</a>

<a name='conditionals'>Условни изрази и равенства</a>

<a name='blocks'>Блокове</a>

<a name='comments'>Коментари</a>


  **[[⬆]](#TOC)**


## <a name='whitespace'>Празни полета</a>

- Използвайте табулации с 2 празни полета

  ```javascript
  // лоша практика
  function() {
  ∙∙∙∙var name;
  }

  // лоша практика
  function() {
  ∙var name;
  }

  // добра практика
  function() {
  ∙∙var name;
  }
  ```
- Поставяйте 1 празно пространство преди начална скоба.

  ```javascript
  // лоша практика
  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'
  });
  ```
- Поставяйте празен ред в края на файл.

  ```javascript
  // лоша практика
  (function(global) {
    // ...stuff...
  })(this);
  ```

  ```javascript
  // добра практика
  (function(global) {
    // ...stuff...
  })(this);

  ```

- Използвайте йерархично подравняване при дълги вериги от методи.

  ```javascript
  // лоша практика
  $('#items').find('.selected').highlight().end().find('.open').updateCount();

  // добра практика
  $('#items')
    .find('.selected')
      .highlight()
      .end()
    .find('.open')
      .updateCount();

  // лоша практика
  var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
      .attr('width',  (radius + margin) * 2).append('svg:g')
      .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
      .call(tron.led);

  // добра практика
  var leds = stage.selectAll('.led')
      .data(data)
    .enter().append('svg:svg')
      .class('led', true)
      .attr('width',  (radius + margin) * 2)
    .append('svg:g')
      .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
      .call(tron.led);
  ```

  **[[⬆]](#TOC)**

## <a name='commas'>Запетаи</a>

- Запетая на нов ред: **НЕ.**

  ```javascript
  // лоша практика
  var once
    , upon
    , aTime;

  // добра практика
  var once,
      upon,
      aTime;

  // лоша практика
  var hero = {
      firstName: 'Bob'
    , lastName: 'Parr'
    , heroName: 'Mr. Incredible'
    , superPower: 'strength'
  };

  // добра практика
  var hero = {
    firstName: 'Bob',
    lastName: 'Parr',
    heroName: 'Mr. Incredible',
    superPower: 'strength'
  };
  ```

- Допълнителна запетая в края: **НЕ.** Може да създаде проблем с IE6/7 и IE9. Също, в някои реализации на ES3 може да добави дължина към масив ако има такава запетая. Това е изяснено в ES5 ([source](http://es5.github.io/#D)):

> Издание 5 изяснява факта, че запетая в края на ArrayInitialiser не добавя дължина към масива. Това не е семантина промяна от издание 3, но някои реализации може да бъркат това.

  ```javascript
  // лоша практика
  var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn',
  };

  var heroes = [
    'Batman',
    'Superman',
  ];

  // добра практика
  var hero = {
    firstName: 'Kevin',
    lastName: 'Flynn'
  };

  var heroes = [
    'Batman',
    'Superman'
  ];
  ```

  **[[⬆]](#TOC)**


## <a name='semicolons'>Точка и запетая</a>

- **ДА.**

  ```javascript
  // лоша практика
  (function() {
    var name = 'Skywalker'
    return name
  })()

  // добра практика
  (function() {
    var name = 'Skywalker';
    return name;
  })();

  // добра практика
  ;(function() {
    var name = 'Skywalker';
    return name;
  })();
  ```

  **[[⬆]](#TOC)**


## <a name='type-coercion'>Преобразуване на типове</a>

- Изпълнявайте преобразуването на типове в началото.
- Низ:

  ```javascript
  //  => this.reviewScore = 9;

  // лоша практика
  var totalScore = this.reviewScore + '';

  // добра практика
  var totalScore = '' + this.reviewScore;

  // лоша практика
  var totalScore = '' + this.reviewScore + ' total score';

  // добра практика
  var totalScore = this.reviewScore + ' total score';
  ```

- Use `parseInt` for Numbers and always with a radix for type casting.

  ```javascript
  var inputValue = '4';

  // лоша практика
  var val = new Number(inputValue);

  // лоша практика
  var val = +inputValue;

  // лоша практика
  var val = inputValue >> 0;

  // лоша практика
  var val = parseInt(inputValue);

  // добра практика
  var val = Number(inputValue);

  // добра практика
  var val = parseInt(inputValue, 10);
  ```


- В случай, че решите да сте палави с  `parseInt` и това ви е ахилесовата пета и е нужно да използате смяна на битове [performance reasons](http://jsperf.com/coercion-vs-casting/3), оставете коментар какво и защо правите.

- **Забележка:** Бъдете предпазливи като използвате промяна на битове. Числата са представени чрез [64-bit values](http://es5.github.io/#x4.3.19), но смяната на битове винаги връща 32-битов интиджер ([source](http://es5.github.io/#x11.7)). Смяната на битове може да доведе до неочаквано поведени при числови стойности на 32 бита. [Discussion](https://github.com/airbnb/javascript/issues/109)

  ```javascript
  // добра практика
  /**
   * parseInt беше причина кода ми да е бавен.
   * Промяната на битове в стринга
   * към числа го направи по-бърз.
   */
  var val = inputValue >> 0;
  ```

- Булеви стойности:

  ```javascript
  var age = 0;

  // лоша практика
  var hasAge = new Boolean(age);

  // добра практика
  var hasAge = Boolean(age);

  // добра практика
  var hasAge = !!age;
  ```

  **[[⬆]](#TOC)**


## <a name='naming-conventions'>Наименуване практики</a>

- Избягвайте имена от 1 буква. Обяснявайте какво наименувате.

  ```javascript
  // лоша практика
  function q() {
    // ...stuff...
  }

  // добра практика
  function query() {
    // ..stuff..
  }
  ```

- Използвайте camelCase, когато именовате обекти, функции, и инстанции

  ```javascript
  // лоша практика
  var OBJEcttsssss = {};
  var this_is_my_object = {};
  function c() {};
  var u = new user({
    name: 'Bob Parr'
  });

  // добра практика
  var thisIsMyObject = {};
  function thisIsMyFunction() {};
  var user = new User({
    name: 'Bob Parr'
  });
  ```

- Използвайте PascalCase когато именувате конструктори или класове

  ```javascript
  // лоша практика
  function user(options) {
    this.name = options.name;
  }

  var лоша практика = new user({
    name: 'nope'
  });

  // добра практика
  function User(options) {
    this.name = options.name;
  }

  var добра практика = new User({
    name: 'yup'
  });
  ```

- Използвайте долно тире в началото `_`, когато именувате частни променливи

  ```javascript
  // лоша практика
  this.__firstName__ = 'Panda';
  this.firstName_ = 'Panda';

  // добра практика
  this._firstName = 'Panda';
  ```

- Когато използвате референции към `this` използвайте `_this`.

  ```javascript
  // лоша практика
  function() {
    var self = this;
    return function() {
      console.log(self);
    };
  }

  // лоша практика
  function() {
    var that = this;
    return function() {
      console.log(that);
    };
  }

  // добра практика
  function() {
    var _this = this;
    return function() {
      console.log(_this);
    };
  }
  ```

- Именувайте си функцийте. Това е добра практика за проследяване на стака.

  ```javascript
  // лоша практика
  var log = function(msg) {
    console.log(msg);
  };

  // добра практика
  var log = function log(msg) {
    console.log(msg);
  };
  ```

  **[[⬆]](#TOC)**


## <a name='accessors'>Достъпване</a>

- Не са необходими функции за променливи
- Ако има - ползвайте подобни на  getVal() и setVal('hello')

  ```javascript
  // лоша практика
  dragon.age();

  // добра практика
  dragon.getAge();

  // лоша практика
  dragon.age(25);

  // добра практика
  dragon.setAge(25);
  ```

- Ако променлива е булева стойност, използвайте isVal() или hasVal()

  ```javascript
  // лоша практика
  if (!dragon.age()) {
    return false;
  }

  // добра практика
  if (!dragon.hasAge()) {
    return false;
  }
  ```

- Може да се създадат get() и set() функции, но бъдете постоянни с тях.

  ```javascript
  function Jedi(options) {
    options || (options = {});
    var lightsaber = options.lightsaber || 'blue';
    this.set('lightsaber', lightsaber);
  }

  Jedi.prototype.set = function(key, val) {
    this[key] = val;
  };

  Jedi.prototype.get = function(key) {
    return this[key];
  };
  ```

  **[[⬆]](#TOC)**


## <a name='constructors'>Конструктор</a>

- Присвоявайте методи на прототипа обект, вместо да пренаписвате прототипа с нов обект. Пренаписването на прототипа прави наследяването невъзможно: от задаване на нова стойност на прототипа, пренаписване базата!

  ```javascript
  function Jedi() {
    console.log('new jedi');
  }

  // лоша практика
  Jedi.prototype = {
    fight: function fight() {
      console.log('fighting');
    },

    block: function block() {
      console.log('blocking');
    }
  };

  // добра практика
  Jedi.prototype.fight = function fight() {
    console.log('fighting');
  };

  Jedi.prototype.block = function block() {
    console.log('blocking');
  };
  ```

- Методите могат да връщат `this` помагайки с навързването на методи.

  ```javascript
  // лоша практика
  Jedi.prototype.jump = function() {
    this.jumping = true;
    return true;
  };

  Jedi.prototype.setHeight = function(height) {
    this.height = height;
  };

  var luke = new Jedi();
  luke.jump(); // => true
  luke.setHeight(20) // => undefined

  // добра практика
  Jedi.prototype.jump = function() {
    this.jumping = true;
    return this;
  };

  Jedi.prototype.setHeight = function(height) {
    this.height = height;
    return this;
  };

  var luke = new Jedi();

  luke.jump()
    .setHeight(20);
  ```


  - Може да дефинира и toString() метод, просто бъдете сигурни, че няма странични ефекти.

  ```javascript
  function Jedi(options) {
    options || (options = {});
    this.name = options.name || 'no name';
  }

  Jedi.prototype.getName = function getName() {
    return this.name;
  };

  Jedi.prototype.toString = function toString() {
    return 'Jedi - ' + this.getName();
  };
  ```

  **[[⬆]](#TOC)**


## <a name='events'>Събития</a>

  ```javascript 
  // лоша практика
  $(this).trigger('listingUpdated', listing.id);

  ...

  $(this).on('listingUpdated', function(e, listingId) {
    // do something with listingId
  });
  ```

  предпочитайте:

  ```javascript
  // добра практика
  $(this).trigger('listingUpdated', { listingId : listing.id });

  ...

  $(this).on('listingUpdated', function(e, data) {
    // do something with data.listingId
  });
  ```

**[[⬆]](#TOC)**


## <a name='modules'>Модули</a>

- Модул трябва да започва с `!`. Това осигурява, че дори друг модул да е забравил да постави на края точка и запетая, няма да има грешки в продукция, когато скриптовете се конкатенират. [Explanation](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933)

- Файлът се наименува с camelCase, в папка със същото име.


- Добавете метод, казващ се noConflict(), поставящ експортираните модули към предишна версия и връщащ този.

- Декларирайте `'use strict';` в началото на модул.

  ```javascript
  // fancyInput/fancyInput.js

  !function(global) {
    'use strict';

    var previousFancyInput = global.FancyInput;

    function FancyInput(options) {
      this.options = options || {};
    }

    FancyInput.noConflict = function noConflict() {
      global.FancyInput = previousFancyInput;
      return FancyInput;
    };

    global.FancyInput = FancyInput;
  }(this);
  ```

  **[[⬆]](#TOC)**


## <a name='jquery'>jQuery</a>

- Поставете jQuery обекти променливи с `$`.

  ```javascript
  // лоша практика
  var sidebar = $('.sidebar');

  // добра практика
  var $sidebar = $('.sidebar');
  ``` 

  ```javascript
  // лоша практика
  function setSidebar() {
    $('.sidebar').hide();

    // ...stuff...

    $('.sidebar').css({
      'background-color': 'pink'
    });
  }

  // добра практика
  function setSidebar() {
    var $sidebar = $('.sidebar');
    $sidebar.hide();

    // ...stuff...

    $sidebar.css({
      'background-color': 'pink'
    });
  }
  ```

//- For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
- За DOM търсене използвайте каскадно `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
- Use `find` with scoped jQuery object queries.
- Използвайте `find` в jQuery за по-лесно намиране в скоуп.

  ```javascript
  // лоша практика
  $('ul', '.sidebar').hide();

  // лоша практика
  $('.sidebar').find('ul').hide();

  // добра практика
  $('.sidebar ul').hide();

  // добра практика
  $('.sidebar > ul').hide();

  // добра практика
  $sidebar.find('ul');
  ```

  **[[⬆]](#TOC)**


## <a name='es5'>ECMAScript 5 Съвместимост</a>

- Отнася се [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/)

**[[⬆]](#TOC)**


## <a name='testing'>Тестване</a>

- **ДА.**

  ```javascript
  function() {
    return true;
  }
  ```

  **[[⬆]](#TOC)**


## <a name='performance'>Изпълнение</a>

- [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)
- [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)
- [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)
- [Bang Function](http://jsperf.com/bang-function)
- [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13)
- [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text)
- [Long String Concatenation](http://jsperf.com/ya-string-concat)
- Loading...

**[[⬆]](#TOC)**


## <a name='resources'>Ресурси</a>


**Прочетете това**

- [Annotated ECMAScript 5.1](http://es5.github.com/)

**Други стилови ръководства**

- [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
- [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
- [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)

**Други стилове**

- [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen
- [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52)
- [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript)

**Допълнителни**

- [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
- [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer

**Книги**

- [JavaScript: The good Parts](http://www.amazon.com/JavaScript-good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
- [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
- [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X)  - Ross Harmes and Dustin Diaz
- [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
- [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
- [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
- [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
- [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
- [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault
- [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
- [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
- [JSBooks](http://jsbooks.revolunet.com/)

**Блогове**

- [DailyJS](http://dailyjs.com/)
- [JavaScript Weekly](http://javascriptweekly.com/)
- [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/)
- [Bocoup Weblog](http://weblog.bocoup.com/)
- [Adequately good](http://www.adequatelygood.com/)
- [NCZOnline](http://www.nczonline.net/)
- [Perfection Kills](http://perfectionkills.com/)
- [Ben Alman](http://benalman.com/)
- [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
- [Dustin Diaz](http://dustindiaz.com/)
- [nettuts](http://net.tutsplus.com/?s=javascript)

**[[⬆]](#TOC)**

## <a name='in-the-wild'>Къде се използват тези практики</a>


- **Aan Zee**: [AanZee/javascript](https://github.com/AanZee/javascript)
- **Airbnb**: [airbnb/javascript](https://github.com/airbnb/javascript)
- **American Insitutes for Research**: [AIRAST/javascript](https://github.com/AIRAST/javascript)
- **Compass Learning**: [compasslearning/javascript-style-guide](https://github.com/compasslearning/javascript-style-guide)
- **ExactTarget**: [ExactTarget/javascript](https://github.com/ExactTarget/javascript)
- **Gawker Media**: [gawkermedia/javascript](https://github.com/gawkermedia/javascript)
- **GeneralElectric**: [GeneralElectric/javascript](https://github.com/GeneralElectric/javascript)
- **GoodData**: [gooddata/gdc-js-style](https://github.com/gooddata/gdc-js-style)
- **Grooveshark**: [grooveshark/javascript](https://github.com/grooveshark/javascript)
- **How About We**: [howaboutwe/javascript](https://github.com/howaboutwe/javascript)
- **Mighty Spring**: [mightyspring/javascript](https://github.com/mightyspring/javascript)
- **MinnPost**: [MinnPost/javascript](https://github.com/MinnPost/javascript)
- **ModCloth**: [modcloth/javascript](https://github.com/modcloth/javascript)
- **National Geographic**: [natgeo/javascript](https://github.com/natgeo/javascript)
- **National Park Service**: [nationalparkservice/javascript](https://github.com/nationalparkservice/javascript)
- **Razorfish**: [razorfish/javascript-style-guide](https://github.com/razorfish/javascript-style-guide)
- **Shutterfly**: [shutterfly/javascript](https://github.com/shutterfly/javascript)
- **Userify**: [userify/javascript](https://github.com/userify/javascript)
- **Zillow**: [zillow/javascript](https://github.com/zillow/javascript)
- **ZocDoc**: [ZocDoc/javascript](https://github.com/ZocDoc/javascript)

## <a name='translation'>Преводи</a>

Други преводи

- :de: **Немски**: [timofurrer/javascript-style-guide](https://github.com/timofurrer/javascript-style-guide)
- :jp: **Японски**: [mitsuruog/javacript-style-guide](https://github.com/mitsuruog/javacript-style-guide)
- :br: **Портогалски**: [armoucar/javascript-style-guide](https://github.com/armoucar/javascript-style-guide)
- :cn: **Китайски**: [adamlu/javascript-style-guide](https://github.com/adamlu/javascript-style-guide)
- :es: **Испански**: [paolocarrasco/javascript-style-guide](https://github.com/paolocarrasco/javascript-style-guide)
- :kr: **Корейски**: [tipjs/javascript-style-guide](https://github.com/tipjs/javascript-style-guide)
- :fr: **Френски**: [nmussy/javascript-style-guide](https://github.com/nmussy/javascript-style-guide)
- :ru: **Руски**: [sbezludny/javascript-style-guide](https://github.com/sbezludny/javascript-style-guide)
- :bg: **Български**: [borislavvv/javascript-style-guide](https://github.com/sbezludny/javascript-style-guide)

## <a name='guide-guide'>JavaScript Стилово ръководство</a>

- [Reference](https://github.com/airbnb/javascript/wiki/The-JavaScript-Style-Guide-Guide)

## <a name='authors'>Сътрудници</a>

- [View Contributors](https://github.com/airbnb/javascript/graphs/contributors)


## <a name='license'>Лиценз</a>

(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.

**[[⬆]](#TOC)**

# };