Това е развиващ се документ и всички идеи за развиване на кода са са винаги добре дошли. Може да сътрудничите: fork, clone, branch, commit, push, pull request.
- Rick Waldron @rwaldron, github
- Mathias Bynens @mathias, github
- Schalk Neethling @ossreleasefeed, github
- Kit Cambridge @kitcambridge, github
- Raynos github
- Matias Arriola @MatiasArriola, github
- John Fischer @jfroffice, github
- Idan Gazit @idangazit, github
- Leo Balter @leobalter, github
- Breno Oliveira @garu_rj, github
- Leo Beto Souza @leobetosouza, github
- Ryuichi Okumura @okuryu, github
- Pascal Precht @PascalPrecht, github
- EngForDev engfordev - Hwan Min Hong / MinTaek Kwon @leoinsight / Tw Shim @marocchino, github / Nassol Kim @nassol99, github / Juntai Park @rkJun, github / Minkyu Shim / Gangmin Won / Justin Yoo @justinchronicle / Daeyup Lee
- Marco Trulla @marcotrulla, github
- Alex Navasardyan @alexnavasardyan, github
- Mihai Paun @mihaipaun, github
- Evgeny Mandrikov @_godin_, github
- Sofish Lin @sofish, github
- Дејан Димић @dejan_dimic, github
- Miloš Gavrilović @gavrisimo, github
- Firede @firede github
- monkadd github
- Stephan Lindauer @stephanlindauer, github
- Thomas P @dragon5689 github
- Yotam Ofek @yotamofek github
- Borislav Banchev github
Целият код в една база данни трябва да изглежда всякаш един човек го е писал, без значение колко хора са помагали.
Следващият списък подчертава практиките, които авторът на оригиналния документ използва; всички допълвания към документа трябва да ползват тези насоки.
Ребека Мърфи
"Част от това да бъдеш добър ръководител на проект е да разбереш, че писането на код за себе си е Лоша Идея™. Ако хиляди хора ти ползват кода, то пиши код с максимална ясното, не по лични предпочитания как да бъдеш умен в твоите си разбирания."
Идан Газит
- Немски
- Френски
- Испански
- Португалски
- Корейски
- Японски
- Италиански
- Руски
- Румънски
- 简体中文
- Сръбски
- Сръбски - латиница
- Български
Следните неща да се вземат в предвид 1) непълно, и 2) Изисква препрочитане. Не винаги съм съгласен със стила на авторите по-надолу, но едно е сигурно: Те са последателни, нещо повече - те са авторитети в езика.
- Baseline For Front End Developers
- Eloquent JavaScript
- JavaScript, JavaScript
- Adventures in JavaScript Development
- Perfection Kills
- Douglas Crockford's Wrrrld Wide Web
- JS Assessment
- Leveraging Code Quality Tools by Anton Kovalyov
Проектите винаги трябва да се опитват някакви правила по които да могат да бъдат проверени, тествани и компресирани в подготовката за продукционна версия. За тази задача, grunt от Ben Alman е безценен проект и официално е заменило "kits/" директоритите от това хранилище.
Проектите трябва да включват някаква форма на юнит тетване, справки, изпъление или функционално тестване. 'Use case' демонстрациите НЕ СА "тестове". Това е списък със заверени тестващи прибори.
- Празни полета
- Красив синтаксис
- Проверка на типове(Бладарение на jQuery Core стилови насоки)
- Условни уравнения
- Практически стил
- Именуване
- Смесено
- Обекти
- Коментари
- Едноезиков код
Следващата секция очертава разумни стилови насоки за модерно JavaScript писане без намерение да е норма. Най-важното си остава закона за последователно стилизиран код. Какъвто и стил да изберете за проектът ви, трябва да е закон. Може да давате връзка към този документ за стил на вашия проект.
- Никога не смесвайте табулации и празни полета.
- Когато започвате проект, преди да пишете код, изберете празно поле или табулация, и зачитайте този закон.
- За четимост, се предлага да се настрой редактора на 2 празни полета — това значи 2 празни полета да се равняват на 1 табулация.
- Ако редакторът ви го поддържа, работете винаги със "покажи невидимите" пуснато. Ползата от тази практика е :
- Принудително постоянство
- Премахване на последно празно пространство от края на реда
-
A. Големи и малки скоби, нов ред
// if/else/for/while/try винаги имат празни пространства, и се пишат на няколко реда // това насърчава четимостта // 2.A.1.1 // Пример за трудно четим синтаксис if(condition) doSomething(); while(condition) iterating++; for(var i=0;i<100;i++) someIterativeFn(); // 2.A.1.1 // Ползвайте празно пространство за повишаване на четливостта if ( condition ) { // statements } while ( condition ) { // statements } for ( var i = 0; i < 100; i++ ) { // statements } // Даже по-добре: var i, length = 100; for ( i = 0; i < length; i++ ) { // statements } // Или... var i = 0, length = 100; for ( ; i < length; i++ ) { // statements } var prop; for ( prop in object ) { // statements } if ( true ) { // statements } else { // statements }
B. Придаване на стойност, декларации, функции ( наименовани, изрази, конструктури )
// 2.B.1.1 // Променливи var foo = "bar", num = 1, undef; // Литерали: var array = [], object = {}; // 2.B.1.2 // Използвайте едно `var` на скоуп (функция) насърчава четимостта // и пази декларациите от бъркотии (по-малко писане също) // зле var foo = ""; var bar = ""; var qux; // добре var foo = "", bar = "", quux; // или.. var // Comment on these foo = "", bar = "", quux; // 2.B.1.3 // var декларациите винаги трябва да са в началото на скоупа (функцията). // Същото е и за константите от ECMAScript 6. // зле function foo() { // some statements here var bar = "", qux; } // добре function foo() { var bar = "", qux; // all statements after the variables declarations. }
// 2.B.2.1 // Деклариране на именовани функции function foo( arg1, argN ) { } // Извикване foo( arg1, argN ); // 2.B.2.2 // Именовани функции декларация function square( number ) { return number * number; } // Ползване square( 10 ); // Наистина скалъпен начин за стойност function square( number, callback ) { callback( number * number ); } square( 10, function( square ) { // callback statements }); // 2.B.2.3 // Изрази функции var square = function( number ) { // Return something valuable and relevant return number * number; }; // Функции изрази с имена var factorial = function factorial( number ) { if ( number < 2 ) { return 1; } return number * factorial( number - 1 ); }; // 2.B.2.4 // Конструктури function FooBar( options ) { this.options = options; } // Извикване var fooBar = new FooBar({ a: "alpha" }); fooBar.options; // { a: "alpha" }
C. Изключения, леко отклонение
// 2.C.1.1 // Функции с колбек foo(function() { }); // Функцията приема масив, без празни полета foo([ "alpha", "beta" ]); // 2.C.1.2 // Функция, приемаща обект, няма празно поле foo({ a: "alpha", b: "beta" }); // Аргумент един низ, няма разно поле foo("bar"); // Вътрешни скоби, няма празно поле if ( !("foo" in obj) ) { }
D. Последователността винаги е по-добре
Във секции 2.A-2.C, празните полета се препоръчват с цел последователност при писането на код. Важно е да се разбере, че трябва да се избере един модел на писане в целия проект.
// 2.D.1.1 if (condition) { // statements } while (condition) { // statements } for (var i = 0; i < 100; i++) { // statements } if (true) { // statements } else { // statements }
E. Кавички
Няма значение дали се избира единични или двойни кавички, няма разлика при интерпретирането им. What НАЙ-ВАЖНОТО е да е консистентен кода. Не смесвайте използването на кавички в проекта. Изберете един стил и се придържайте към него.
F. Край на редове и празни редове
Празните полета могат много да затруднят четимостта когато са наслагани хаотично. Добре да се премахват в края на реда.
-
Проверяване на типове (Благодарности на jQuery Core Style Guidelines)
A. Реални типове
Низ:
typeof variable === "string"
Число:
typeof variable === "number"
Булева стойност:
typeof variable === "boolean"
Обект:
typeof variable === "object"
Масив:
Array.isArray( arrayLikeObject ) (wherever possible)
Разклонение:
elem.nodeType === 1
null:
variable === null
null или undefined:
variable == null
undefined:
Глобални променливи:
typeof variable === "undefined"
Локални променливи:
variable === undefined
Полета:
object.prop === undefined object.hasOwnProperty( prop ) "prop" in object
B. Прехвърляне към тип
Помислете върху последиците от следното...
От този HTML:
<input type="text" id="foo-input" value="1">
// 3.B.1.1 // `foo` е деклариран със стойност `0` и типът му е `number` var foo = 0; // typeof foo; // "number" ... // Някъде по-надолу в кода трябва да се промени `foo` // с нова стойност, извлечена от input елемента foo = document.getElementById("foo-input").value; // Ако се тества `typeof foo` резултатът ще бъде `string` // Това значи, че ако има логика, която тества `foo` така: if ( foo === 1 ) { importantTask(); } // `importantTask()` няма да бъде извикана дори `foo` като има стойност "1" // 3.B.1.2 // Това може да се реши като се използва унарните + или - операции за прехвърляне на тип: foo = +document.getElementById("foo-input").value; // ^ унарният оператор ще конвертира дясната страна към число // typeof foo; // "number" if ( foo === 1 ) { importantTask(); } // `importantTask()` will be called // `importantTask()` ще се извика
Ето някои общи случаи с използване на принудително преобразуване на типове:
// 3.B.2.1 var number = 1, string = "1", bool = false; number; // 1 number + ""; // "1" string; // "1" +string; // 1 +string++; // 1 string; // 2 bool; // false +bool; // 0 bool + ""; // "false"
// 3.B.2.2 var number = 1, string = "1", bool = true; string === number; // false string === number + ""; // true +string === number; // true bool === number; // false +bool === number; // true bool === string; // false bool === !!string; // true
// 3.B.2.3 var array = [ "a", "b", "c" ]; !!~array.indexOf("a"); // true !!~array.indexOf("b"); // true !!~array.indexOf("c"); // true !!~array.indexOf("d"); // false // Горното може да се разглежда като ненужно хитро // Предпочитайте очевидния подход за сравняване на върната стойност с // indexOf, like: if ( array.indexOf( "a" ) >= 0 ) { // ... }
// 3.B.2.4 var num = 2.5; parseInt( num, 10 ); // същото като... ~~num; num >> 0; num >>> 0; // All result in 2 // Имайте впредвид, че отрицателните числа ще се разглеждат различно... var neg = -2.5; parseInt( neg, 10 ); // е същото като... ~~neg; neg >> 0; // Резултатът е -2 // Въпреки това... neg >>> 0; // Резултатът е 4294967294
-
// 4.1.1 // Когато проверявате дали масив има дължина, // вместо това: if ( array.length > 0 ) ... // ...проверявайте за вярност така: if ( array.length ) ... // 4.1.2 // Когато проверявате дали масив е празен, // вместо това: if ( array.length === 0 ) ... // ...проверявайте така: if ( !array.length ) ... // 4.1.3 // Когато проверявате низ дали е празен // вместо това: if ( string !== "" ) ... // ...проверявайте така if ( string ) ... // 4.1.4 // Когато проверявате дали низ _е_ празен, // вместо това: if ( string === "" ) ... // ...проверявайте така: if ( !string ) ... // 4.1.5 // Когато проверявате дали референция е true // вместо това: if ( foo === true ) ... // ...ползвайте вградените възможности if ( foo ) ... // 4.1.6 // Когато се проверява дали референция е празна, // вместо това: if ( foo === false ) ... // ...ползвайте обратната стойност на правилният вариант if ( !foo ) ... // ...Внимавайте, това също може да съвпада с : 0, "", null, undefined, NaN // Ако _ТРЯБВА_ да се тества за false, ползвайте if ( foo === false ) ... // 4.1.7 // Когато проверявате дали референция може да е null или undefined, но НЕ false, "" или 0, // вместо това: if ( foo === null || foo === undefined ) ... // ...ползвайте == типово прехвърляне така: if ( foo == null ) ... // Запомнете, ползвайки == ще приравни `null` към `null` и `undefined` // но не и към `false`, "" или 0 null == undefined
Винаги проверявайте за най-точни резултати, горното са насоки, не догма
// 4.2.1 // Прехвърляне на типове и проверка бележки // Предпочитайте `===` над `==` (освен ако случая не изисква свободна типова оценка) // === не прехвърля тип, което значи това: "1" === 1; // false // == прехвърля тип, което значи: "1" == 1; // true // 4.2.2 // Булеви стойности, вярно, грешно // Булеви стойности: true, false // Вярно: "foo", 1 // Грешно: "", 0, null, undefined, NaN, void 0
-
// 5.1.1 // Практически модул (function( global ) { var Module = (function() { var data = "secret"; return { // Някаква булева стойност bool: true, // Някакъв низ string: "a string", // Масив array: [ 1, 2, 3, 4 ], // Обект object: { lang: "en-Us" }, getData: function() { // стойността на `data` return data; }, setData: function( value ) { // задай стойност `data` и я върни return ( data = value ); } }; })(); // Друг код // Разкрийте модула на глобалния обект global.Module = Module; })( this );
// 5.2.1 // Практически конструктор (function( global ) { function Ctor( foo ) { this.foo = foo; return this; } Ctor.prototype.getFoo = function() { return this.foo; }; Ctor.prototype.setFoo = function( val ) { return ( this.foo = val ); }; // За извикване на конструктор без `new`, може така: var ctor = function( foo ) { return new Ctor( foo ); }; // открий конструктора на глобалния обект global.ctor = ctor; })( this );
-
A. Ти не си човек-компилатор, не се и опитвай да бъдеш.
Пример за лош код:
// 6.A.1.1 // Неправилни имена function q(s) { return document.querySelectorAll(s); } var i,a=[],els=q("#foo"); for(i=0;i<els.length;i++){a.push(els[i]);}
Всеки може да е писал такъв код. Дано това да спре от днес.
Ето някакъв код с по-добри имена:
// 6.A.2.1 // Пример за код с подобрени имена function query( selector ) { return document.querySelectorAll( selector ); } var idx = 0, elements = [], matches = query("#foo"), length = matches.length; for ( ; idx < length; idx++ ) { elements.push( matches[ idx ] ); }
Някои допълнителни показатели за имена:
// 6.A.3.1 // Именоване на низ `dog` is a string // 6.A.3.2 // Именоване на масив `dogs` is an array of `dog` strings // 6.A.3.3 // Функции, обекти, инстанции, други camelCase; function and var declarations // 6.A.3.4 // Конструктори, прототипи, други PascalCase; constructor function // 6.A.3.5 // Регулярни изрази rDesc = //; // 6.A.3.6 // От Google Closure Library Style Guide functionNamesLikeThis; variableNamesLikeThis; ConstructorNamesLikeThis; EnumNamesLikeThis; methodNamesLikeThis; SYMBOLIC_CONSTANTS_LIKE_THIS;
B. Лицата на
this
Предпочитайте
.bind( this )
предcall
andapply
или еквивалент, когато е възможно разбира се.// 6.B.1 function Device( opts ) { this.value = null; // open an async stream, // this will be called continuously stream.read( opts.path, function( data ) { // Update this instance's current value // with the most recent value from the // data stream this.value = data; }.bind(this) ); // Throttle the frequency of events emitted from // this Device instance setInterval(function() { // Emit a throttled event this.emit("event"); }.bind(this), opts.freq || 100 ); } // Just pretend we've inherited EventEmitter ;)
Ако няма как, функционални еквиваленти на
.bind
съществуват в много модерни библиотеки.// 6.B.2 // eg. lodash/underscore, _.bind() function Device( opts ) { this.value = null; stream.read( opts.path, _.bind(function( data ) { this.value = data; }, this) ); setInterval(_.bind(function() { this.emit("event"); }, this), opts.freq || 100 ); } // eg. jQuery.proxy function Device( opts ) { this.value = null; stream.read( opts.path, jQuery.proxy(function( data ) { this.value = data; }, this) ); setInterval( jQuery.proxy(function() { this.emit("event"); }, this), opts.freq || 100 ); } // eg. dojo.hitch function Device( opts ) { this.value = null; stream.read( opts.path, dojo.hitch( this, function( data ) { this.value = data; }) ); setInterval( dojo.hitch( this, function() { this.emit("event"); }), opts.freq || 100 ); }
Като последно средство, създавайте псевдоним на
this
използвайкиself
като идентификатор. Това не е от най-добрите практики и са възможни много грешки.// 6.B.3 function Device( opts ) { var self = this; this.value = null; stream.read( opts.path, function( data ) { self.value = data; }); setInterval(function() { self.emit("event"); }, opts.freq || 100 ); }
C. Използвайте
thisArg
Няколко прототипа на методи в ES 5.1 идват с включено
thisArg
, което трябва да се използва, когато е възможно.// 6.C.1 var obj; obj = { f: "foo", b: "bar", q: "qux" }; Object.keys( obj ).forEach(function( key ) { // |this| се отнася към `obj` console.log( this[ key ] ); }, obj ); // <-- последният arg е `thisArg` // Принтиране... // "foo" // "bar" // "qux"
thisArg
може да се използва сArray.prototype.every
,Array.prototype.forEach
,Array.prototype.some
,Array.prototype.map
,Array.prototype.filter
-
Тази секция цели да илюстрира идеи и концепции, които не са догма, но за сметка на това поущряват практики с цел намиране на по-добри начини за съвместни програмни JavaScript задачи.
A. Използването на
switch
може да се избегне.Въпреки, че има драстично подобряване на изпълнението на
switch
в последните версии на Firefox и Chrome. http://jsperf.com/switch-vs-object-literal-vs-moduleЗабележителни промени могат да се забележат и тук: rwaldron#13
// 7.A.1.1 // Примерен switch switch( foo ) { case "alpha": alpha(); break; case "beta": beta(); break; default: // something to default to break; } // 7.A.1.2 // Алтернативен подход, предлагащ преизползване // използва обект за запазване на "cases" и функция за делегат var cases, delegator; // Example returns for illustration only. cases = { alpha: function() { // statements // a return return [ "Alpha", arguments.length ]; }, beta: function() { // statements // a return return [ "Beta", arguments.length ]; }, _default: function() { // statements // a return return [ "Default", arguments.length ]; } }; delegator = function() { var args, key, delegate; // Transform arguments list into an array args = [].slice.call( arguments ); // shift the case key from the arguments key = args.shift(); // Assign the default case handler delegate = cases._default; // Derive the method to delegate operation to if ( cases.hasOwnProperty( key ) ) { delegate = cases[ key ]; } // The scope arg could be set to something specific, // in this case, |null| will suffice return delegate.apply( null, args ); }; // 7.A.1.3 // Put the API in 7.A.1.2 to work: delegator( "alpha", 1, 2, 3, 4, 5 ); // [ "Alpha", 5 ] // Разбира се `case` може да бъде базиран // на някои случайни условия. var caseKey, someUserInput; // От input? someUserInput = 9; if ( someUserInput > 10 ) { caseKey = "alpha"; } else { caseKey = "beta"; } // или... caseKey = someUserInput > 10 ? "alpha" : "beta"; // и тогава... delegator( caseKey, someUserInput ); // [ "Beta", 1 ] // разбира се... delegator(); // [ "Default", 0 ]
B. Ранните връщания на метод повишават четимостта с пренебрежими разлики в изпълнението
// 7.B.1.1 // зле: function returnLate( foo ) { var ret; if ( foo ) { ret = "foo"; } else { ret = "quux"; } return ret; } // добре: function returnEarly( foo ) { if ( foo ) { return "foo"; } return "quux"; }
-
Най-важният принцип тук е:
За подсилване на концепцията, моля гледайте следната презентация:
<iframe src="http://blip.tv/play/g_Mngr6LegI.html" width="480" height="346" frameborder="0" allowfullscreen></iframe>http://blip.tv/jsconf/jsconf2011-andrew-dupont-everything-is-permitted-extending-built-ins-5211542
-
Програмите трябва да са написани на един език, който и да било, както се диктува от поддържащите разработчици.
Всеки проект, който цитира този документ като основен стил, не приема запетая като начало на форматиране, освен ако не е казано изрично от автора на проекта.
Principles of Writing Consistent, Idiomatic JavaScript by Rick Waldron and Contributors is licensed under a Creative Commons Attribution 3.0 Unported License.
Based on a work at github.com/rwldrn/idiomatic.js.