├── ja
├── CONTRIBUTORS.md
├── Resources.md
├── README.md
├── JavaScript_Performance.md
├── Maintainable_JavaScript.md
├── Preventing_JavaScript_Errors.md
└── Readable_JavaScript.md
├── Resources.md
├── README.md
├── JavaScript_Performance.md
├── Maintainable_JavaScript.md
├── LICENSE
├── Preventing_JavaScript_Errors.md
└── Readable_JavaScript.md
/ja/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | # 本ドキュメントを日本語に翻訳した人たち
2 |
3 | * [Hisashi Nakamura](https://github.com/sunvisor) : [http://www.sunvisor.net](http://www.sunvisor.net/)
4 | * [Shinobu Kawano](https://github.com/shinobukawano) : [http://shinobukawano.com](http://shinobukawano.com/)
5 |
--------------------------------------------------------------------------------
/ja/Resources.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # 学習リソース
6 |
7 | このガイドはAirbnbの[この素晴らしいガイド](https://github.com/airbnb/javascript)からインスピレーションを得ています。ぜひそちらもご一読下さい。
8 |
9 | 本ドキュメントの各所に埋め込んだリンクのページに加えて、下記のページもご覧頂くことを強くお奨めいたします
10 | 。
11 |
12 | - [Code Conventions for the JavaScript Programming Language](http://javascript.crockford.com/code.html) from Douglass Crockford
13 | - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) from Google
14 | - [jQuery JavaScript Style Guide](http://contribute.jquery.org/style-guide/js/) from jQuery
15 | - [A JavaScript Quality Guide](https://github.com/bevacqua/js) from Nicolas Bevacqua
16 | - [Compiler-Friendly Code Guidelines](http://docs.sencha.com/cmd/5.x/cmd_compiler.html) from Sencha
17 |
18 | また、下記の書籍も非常にお奨めです。ぜひご拝読下さい。
19 |
20 | - [JavaScript: The Good Parts](http://) by Douglass Crockford
21 | - [テスト駆動JavaScript](http://) by Christian Johansen
22 | - [JavaScript Ninjaの秘密](http://) by John Resig
23 | - [Maintainable JavaScript](http://) by Nicholas Zakas
24 |
--------------------------------------------------------------------------------
/Resources.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Resources
6 |
7 | The original inspiration for this guide comes from the [fantastic guide](https://github.com/airbnb/javascript)
8 | put together by Airbnb.
9 |
10 | In addition to the many inline links our document contains, we strongly recommend you take a look at the following resources:
11 |
12 | - [Code Conventions for the JavaScript Programming Language](http://javascript.crockford.com/code.html) from Douglass Crockford
13 | - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) from Google
14 | - [jQuery JavaScript Style Guide](http://contribute.jquery.org/style-guide/js/) from jQuery
15 | - [A JavaScript Quality Guide](https://github.com/bevacqua/js) from Nicolas Bevacqua
16 | - [Compiler-Friendly Code Guidelines](http://docs.sencha.com/cmd/5.x/cmd_compiler.html) from Sencha
17 |
18 |
19 | We would also strongly encourage you to read the following books:
20 |
21 | - _JavaScript: The Good Parts_ by Douglass Crockford
22 | - _Test Driven JavaScript Development_ by Christian Johansen
23 | - _Secrets of the JavaScript Ninja_ by John Resig
24 | - _Maintainable JavaScript_ by Nicholas Zakas
25 |
--------------------------------------------------------------------------------
/ja/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # SenchaのJavaScriptスタイルガイド&ベストプラクティス
6 |
7 | この文書は、JavaScriptとHTML5を利用してエンタープライズWebアプリケーションを開発する際のベストプラクティスや推奨事項をまとめたものです。
8 |
9 | 本文書のアドバイスは実際に当社(Sencha)の社内で使われているものです。Senchaフレームワークの構築に使われているスタイルガイドではありますが、他のフレームワークを利用している開発チームであっても有用だと考えています。もちろん、Vanilla JavaScriptの場合(\*)であっても変わりません。
10 |
11 | \*訳注 ... フレームワークを使わずにJavaScriptのコードを書くことを`Vanilla JavaScript`と呼びます。
12 |
13 | ## ミッションステートメント
14 |
15 | 高品質なJavaScriptは何よりも一貫性があり、次の4つの柱によって支えられているものであると固く信じています。
16 |
17 | - **可読性:** 明確で、一目で理解できること
18 | - **保守性:** 一貫性があり、まとまっていること
19 | - **例外の回避:** よくある問題を戦略的に避けていること
20 | - **パフォーマンス:** 常により速い実装を考慮していること
21 |
22 | このスタイルガイドは、JavaScriptとHTML5を利用してエンタープライズWebアプリケーションを構築するための、いくつかの基本原則を提供します。そして、主に中規模から大規模の開発チームを想定しています。
23 |
24 | 本文書の推奨は私たち自身の経験だけでなく、当社のお客様との対話も元にしています。
25 |
26 | ## 教義か方針か
27 |
28 | このスタイルガイドについて、必要以上に気にし過ぎないようにして下さい -- この文書は単なるガイドで、絶対に守らなければならない教義ではありません。
29 |
30 | 本ガイドは「ベストプラクティス」についての網羅的な一覧を目指していません。それよりも、皆さんがよく私たちに質問される関心事について答えようとしています。 それらについては、他の多くの方も [似たような文書](Resources.md) を既に作成されており、全体で明らかな同意が取れていないトピックかと存じます。
31 |
32 | この文書の全体的な目標は、コードの「品質」について私たちが重要だと考えている事柄をあなたが検討する手助けを行うことです。そして最終的には、あなたが読みやすく、保守しやすく、拡張性の高いプロジェクトを作成することを目指しています。 私たちの提案は、高品質なJavaScriptのコードベースを構築する戦略を組み立てる際の、開発チームが考慮すべきベースラインだと考えて頂ければ幸いです。
33 |
34 | # 概要
35 |
36 | 当社でのフレームワークとエンタープライズ・アプリケーションを構築した経験から、この議論については、次の4つの部分に分割させて頂きます。
37 |
38 | 1. [可読性](Readable_JavaScript.md)
39 | 2. [保守性](Maintainable_JavaScript.md)
40 | 3. [例外の回避](Preventing_JavaScript_Errors.md)
41 | 4. [パフォーマンス](JavaScript_Performance.md)
42 |
43 |
44 | これら以上に多くの内容についてカバーすることは、あまり価値がないと思われます。
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Sencha's Guide to JavaScript Style and Best Practices
6 |
7 | The following document contains a series of best practices and recommendations for building enterprise web applications
8 | with JavaScript and HTML5.
9 |
10 | Much of this advice is used internally at Sencha and certainly applies to building applications with the Sencha
11 | frameworks -- but this JavaScript style guide can also help teams building applications with any framework, or
12 | even just vanilla JavaScript.
13 |
14 | ## Mission Statement
15 |
16 | Sencha firmly believes that high quality JavaScript is above all else consistent, and addresses four main pillars:
17 |
18 | - **Readability:** JavaScript code should be clear and easy to understand at first glance
19 | - **Maintainability:** JavaScript code should be consistent and cohesive
20 | - **Error Prevention:** JavaScript code should strategically avoid common problems
21 | - **Performance:** JavaScript code should always consider faster implementations
22 |
23 | This style guide will attempt to provide some ground rules for building enterprise web applications with JavaScript and
24 | HTML5, and as such is intended primarily for medium-to-large development teams.
25 |
26 | These recommendations are based on our own experiences, as well as direct interaction with our enterprise customers.
27 |
28 | ## Dogma vs Doctrine
29 |
30 | Avoid obsessing about code style -- this document is merely a guide, not infallible dogma. It is not intended to be a
31 | comprehensive list of all "best practices", but rather a list of the most common areas on which people ask our
32 | opinions. Many others have created [similar documents](Resources.md) and clearly not everyone agrees on every point.
33 |
34 | The overall goal for this document is to help you evaluate what we consider to be the important aspects of "quality"
35 | code, and ultimately create your own readable, maintainable and scalable JavaScript projects. Our suggestions stand as
36 | a baseline from which your teams should implement your own strategy for building a high quality JavaScript codebase.
37 |
38 | # Outline
39 |
40 | To best articulate Sencha's experience building both frameworks and enterprise applications, we will divide this
41 | discussion into four parts:
42 |
43 | 1. [Readability](Readable_JavaScript.md)
44 | 2. [Maintainability](Maintainable_JavaScript.md)
45 | 3. [Preventing Errors](Preventing_JavaScript_Errors.md)
46 | 4. [Performance](JavaScript_Performance.md)
47 |
48 | It is worth noting that many of the points we will cover might fit into more than one of these pillars.
--------------------------------------------------------------------------------
/ja/JavaScript_Performance.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | #パフォーマンスに気を配りましょう
6 |
7 | > *「パフォーマンスに問題があるときは、パフォーマンスだけが問題である」*
8 |
9 | 開発者なら皆パフォーマンスに気を遣っています -- しかし、開発者はまた、
10 | まずその効率化が必要だということを証明せずにコードの細かな部分を最適化することに時間を費やすことはやめましょう。
11 | 例えば、JavaScriptライブラリやフレームワークで意味がある最適化も、アプリケーションコードではあまり効果がないかもしれません。
12 |
13 | Ext JSやSencha Touchフレームワークを構築した経験と、顧客のアプリケーションへの我々の情報提供を考えると、Sencha はパフォーマンスを改善するためには、次のテクニックを折り紙付きの方法として確認します。
14 |
15 | ###ライブラリまたはフレームワークコード
16 |
17 | - [ループ](#Loops)
18 | - [Try / Catch](#Try_Catch)
19 | - [ページのリフロー](#Page_Reflow)
20 | - [関数ベースのイテレーション](#Function_Based_Iteration)
21 |
22 | ###アプリケーションコード
23 |
24 | Yahooチームはそこに何も加えようがないほどの[卓越したパフォーマンス技術](https://developer.yahoo.com/performance/)をまとめました。
25 |
26 | ですが、Senchaアプリケーションは、できる限り小さなサイズへコードを圧縮するために、ビルドプロセスの一部としてSencha Cmdを用いています。[Compiler-Friendly Code Guidelines](http://docs.sencha.com/cmd/5.x/cmd_compiler.html)
27 | を参照してください。
28 |
29 |
30 | ## ループ
31 |
32 | ループの内側で、関数 (これに関しては他の再利用可能なもの) を宣言してはいけません。
33 | これにより、処理時間、メモリ、ガーベージコレクションのサイクルを無駄遣いします。
34 |
35 | // 悪い
36 | var objectPool = [];
37 |
38 | for (i = 0; i < 10; ++i) {
39 | objectPool.push({
40 | foo: function () {}
41 | });
42 | }
43 |
44 | // 良い
45 | var objectPool = [];
46 |
47 | function bar() {}
48 |
49 | for (i = 0; i < 10; ++i) {
50 | objectPool.push({
51 | foo: bar
52 | });
53 | }
54 |
55 | 配列の長さの計算は、先頭で一度だけ行いその値を変数に格納します。
56 | これにより、ループの各ステップで再計測することを防ぎます。
57 |
58 | // 悪い
59 | var i;
60 | for(i = 0; i < items.length; ++i){
61 | // some code
62 | }
63 |
64 | // 良い
65 | var i, len;
66 | for(i = 0, len = items.length; i < len; ++i){
67 | // some code
68 | }
69 |
70 | // 悪い
71 | var i;
72 | for(i = 0; i < items.getCount(); ++i){
73 | // some code
74 | }
75 |
76 | // 良い
77 | var i, len;
78 | for(i = 0, len = items.getCount(); i < len; ++i){
79 | // some code
80 | }
81 |
82 | `for/in` 形式のループには、[パフォーマンスに悪影響がある](http://jsperf.com/for-in-vs-keys-vs-for)ことが知られていますので、使わないようにしましょう。
83 |
84 | ## Try / Catch
85 |
86 | [パフォーマンスに重大な影響を引き起こすので](http://jsperf.com/try-catch-in-loop-cost/5)
87 | できることなら `try/catch` ステートメントは使わないようにしましょう。
88 |
89 | ## ページ リフロー
90 |
91 | [不必要なページ リフロー](http://www.kellegous.com/j/2013/01/26/layout-performance/)
92 | を起こすパターンを避けましょう。
93 |
94 | リフローは、一部または全てのHTMLページのCSSレイアウトに影響を及ぼす変化が起こります。
95 | エレメントのリフローは、それに引き続いて、すべての子要素と祖先要素に加え、DOM内でそれに続く全ての要素に以降のリフローを引き起こします。
96 |
97 | ブラウザーは自動的にDOMやCSSの変化を経過を追いかけ、何かの位置や外観を変える必要があるときに「リフロー」を発行します。
98 | やっかいなJavaScriptコードではブラウザーに強制的にCSSレイアウトを無効にすることができます -- たとえば、DOMから特定の結果(例えばoffsetHeight)を読むとブラウザー・スタイルのレイアウトの再計算を引き起こすことがあります。
99 | ですから、開発者は、複数のページリフローが起こらないように、非常に注意しなければなりません。
100 |
101 | // 悪い
102 | elementA.className = "a-style"; // スタイルの変更はCSSレイアウトを無効にします
103 | var heightA = elementA.offsetHeight; // オフセットを計算するためにリフローが起こります
104 | elementB.className = "b-style"; // CSSレイアウトが再び無効になります
105 | var heightB = elementB.offsetHeight; // オフセットを計算するためにリフローが起こります
106 |
107 | // 良い
108 | elementA.className = "a-style"; // スタイルの変更はCSSレイアウトを無効にします
109 | elementB.className = "b-style"; // CSSレイアウトはすでに無効ですがまだリフローしません
110 | var heightA = elementA.offsetHeight; // オフセットを計算するためにリフローが起こります
111 | var heightB = elementB.offsetHeight; // CSSレイアウトが更新され、二度目のリフローは起こりません
112 |
113 | ## 関数ベースのイテレーション
114 |
115 | 関数ベースのイテレーションは便利ですが、ループを使うよりも常に遅くなります。
116 |
117 | var myArray = [ 1, 2, 3 ];
118 |
119 | // jQuery
120 | $.each(myArray, function (index, value) {
121 | console.log(index + ": " + value);
122 | });
123 |
124 | // Ext JS 5
125 | Ext.each(myArray, function (value, index) {
126 | console.log(index + ": " + value);
127 | });
128 |
129 | // パフォーマンスは上です!
130 | var len = myArray.length,
131 | i, prop;
132 | for (i = 0; i < len; ++i) {
133 | console.log(i + ": " + myArray[i]);
134 | }
135 |
136 | 関数の宣言は、新しい実行コンテクスト(スコープチェーン)を生成します。
137 | 関数を呼び出して戻り値を取得すると、状態の維持と回復だけでなく、ガーベージコレクションも必要になります -- 一方、イテレーションでは単純に既存のコンテクストの他の場所にジャンプするだけです。
138 |
--------------------------------------------------------------------------------
/JavaScript_Performance.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Keeping an Eye on Performance
6 |
7 | > *"Performance is only a problem if performance is a problem."*
8 |
9 | Every developer should care about performance -- but developers also shouldn't spend time optimizing minute sections
10 | of code without first proving such efficiencies are necessary. For example, optimizations that make sense in a
11 | JavaScript library/framework may have little impact in application code.
12 |
13 | Given our experience building the Ext JS and Touch frameworks and our exposure to customer applications, Sencha has
14 | identified the following techniques as proven methods for improving performance:
15 |
16 | ###Library or Framework Code
17 |
18 | - [Loops](#Loops)
19 | - [Try / Catch](#Try_Catch)
20 | - [Page Reflow](#Page_Reflow)
21 | - [Function-based Iteration](#Function_Based_Iteration)
22 |
23 | ###Application Code
24 |
25 | The Yahoo team put together a document of [exceptional performance techniques](https://developer.yahoo.com/performance/)
26 | that is so thorough it’s hard to add anything.
27 |
28 | Nevertheless, Sencha applications should utilize Sencha Cmd as part of their build process in order to compress the
29 | code to the smallest possible size. Be sure to follow
30 | our [Compiler-Friendly Code Guidelines](http://docs.sencha.com/cmd/5.x/cmd_compiler.html)!
31 |
32 | ## Loops
33 |
34 | Don't declare functions (and for that matter, other re-usable things) inside of loops. It wastes processing time,
35 | memory, and garbage collection cycles:
36 |
37 | // bad
38 | var objectPool = [];
39 |
40 | for (i = 0; i < 10; ++i) {
41 | objectPool.push({
42 | foo: function () {}
43 | });
44 | }
45 |
46 | // good
47 | var objectPool = [];
48 |
49 | function bar () {}
50 |
51 | for (i = 0; i < 10; ++i) {
52 | objectPool.push({
53 | foo: bar
54 | });
55 | }
56 |
57 |
58 | Calculate array length only once upfront and assign its value to a variable. This will prevent measuring it for
59 | every iteration.
60 |
61 | // bad
62 | var i;
63 | for (i = 0; i < items.length; ++i) {
64 | // some code
65 | }
66 |
67 | // good
68 | var i, len;
69 | for (i = 0, len = items.length; i < len; ++i) {
70 | // some code
71 | }
72 |
73 | // bad
74 | var i;
75 | for (i = 0; i < items.getCount(); ++i) {
76 | // some code
77 | }
78 |
79 | // good
80 | var i, len;
81 | for (i = 0, len = items.getCount(); i < len; ++i) {
82 | // some code
83 | }
84 |
85 | Whenever possible avoid `for/in` type of loop as they are known to [negatively impact performance](http://jsperf.com/for-in-vs-keys-vs-for).
86 |
87 |
88 | ## Try / Catch
89 |
90 | Avoid try/catch statements when possible as [they cause significant drags on performance](http://jsperf.com/try-catch-in-loop-cost/5).
91 |
92 | ## Page Reflow
93 |
94 | Avoid patterns that cause [unnecessary page reflows](http://www.kellegous.com/j/2013/01/26/layout-performance/).
95 |
96 | A reflow involves changes that affect the CSS layout of a portion or the entire HTML page. Reflow of an element causes
97 | the subsequent reflow of all child and ancestor elements, as well as any elements following it in the DOM.
98 |
99 | The browser will automatically keep track of DOM and CSS changes, issuing a "reflow" when it needs to change the
100 | position or appearance of something. Unwieldy JavaScript code can force the browser to invalidate the CSS layout -- for
101 | example, reading certain results from the DOM (e.g. offsetHeight) can cause browser style recalculation of layout.
102 | Therefore developers must be incredibly careful to avoid causing multiple page reflows as they will cause application
103 | performance to noticeably lag.
104 |
105 | // bad
106 | elementA.className = "a-style"; // style change invalidates the CSS layout
107 | var heightA = elementA.offsetHeight; // reflow to calculate offset
108 | elementB.className = "b-style"; // invalidates the CSS layout again
109 | var heightB = elementB.offsetHeight; // reflow to calculate offset
110 |
111 | // good
112 | elementA.className = "a-style"; // style change invalidates the CSS layout
113 | elementB.className = "b-style"; // CSS layout is already invalid; but no reflow yet
114 | var heightA = elementA.offsetHeight; // reflow to calculate offset
115 | var heightB = elementB.offsetHeight; // CSS layout is up-to-date; no second reflow!
116 |
117 | ## Function-Based Iteration
118 |
119 | Function-based iteration, while convenient, will always be slower than using a loop.
120 |
121 | var myArray = [ 1, 2, 3 ];
122 |
123 | // jQuery
124 | $.each(myArray, function (index, value) {
125 | console.log(index + ": " + value);
126 | });
127 |
128 | // Ext JS 5
129 | Ext.each(myArray, function (value, index) {
130 | console.log(index + ": " + value);
131 | });
132 |
133 | // BETTER PERFORMANCE!
134 | var len = myArray.length,
135 | i, prop;
136 |
137 | for (i = 0; i < len; ++i) {
138 | console.log(i + ": " + myArray[i]);
139 | }
140 |
141 | Every function invocation creates a new execution context (scope chain). Function calls and returns require state
142 | preservation and restoration, as well as garbage collection -- while iteration simply jumps to another point in
143 | the existing context.
144 |
--------------------------------------------------------------------------------
/ja/Maintainable_JavaScript.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | #保守性の高い JavaScript を書く
6 |
7 | ロバート グラスは、その著書
8 | *Facts and Fallacies of Software Engineering*
9 | (訳注: 邦題「ソフトウエア開発 55の真実と10のウソ」)
10 | において、ソフトウェアのライフタイムを通じてのトータルコストの 80%が保守に費やされると述べています。
11 |
12 | その生涯の上のソフトウェアの総経費の80%もどのようにメンテナンス作業から来るかについて、ロバートGlassは議論する。
13 | それは、バグ修正だけではなく、
14 | 多くの場合「保守」とは新しい機能を既存のアプリケーションに加えることが実際に必要となります。
15 |
16 | この意味は明白です。
17 | 開発者がアプリケーションの保守に多くの時間を費やすのなら、常にコードはそのプロセスを簡単にするように書かれるべきであるということです。
18 |
19 | Sencha は、大きなコードベースを保守することに長期の不一致を軽減するために、次のポイントを優先させることを推奨します。
20 |
21 | - [ファイル毎に一つのクラス](#One_Class_Per_File)
22 | - [変数の宣言](#Declaring_Variables)
23 | - [配列リテラル](#Array_Literals)
24 | - [デバッグ ステートメント](#Debugging_Statements)
25 | - [三項演算子](#Ternary_Operators)
26 | - [正規表現式](#Regular_Expressions)
27 | - [文字列](#Strings)
28 | - [メソッドチェーン](#Method_Chains)
29 |
30 | ## ファイル毎に一つのクラス
31 |
32 | Senchaは、ファイル毎に一つのクラスだけをコード化する習慣を強く推奨します。
33 | そうすると、開発者がどこでコードを見つけのか正確にわかることになるので、アプリケーションを保守、デバッグすることのがより簡単になります。
34 | 完全な名前空間につき、ファイルは『/src/Foo/バー/Baz.js』に位置するかもしれない。
35 |
36 | さらに Sencha は、あなたのファイルに名前をつけ管理する一貫したアプローチを使うことを推奨します。
37 |
38 | ファイル名は定義されるクラス名にマッチし、実際のファイル場所はクラスの名前空間にマッチするようにします。
39 |
40 | たとえば、クラス `Foo.bar.Baz` は、`Baz.js` で定義します。
41 | 完全な名前空間でいくと、このファイルは
42 | `/src/Foo/bar/Baz.js`.
43 | に配置されます。
44 |
45 | ## 変数の宣言
46 |
47 | Sencha は一般的に、変数の宣言はそのスコープの先頭で宣言するというクロックフォードのアドバイスに従います。なぜなら、
48 |
49 | 1. 変数の宣言を見つけるのが簡単になる
50 | 2. 変数のスコープが明白である (JavaScript にはブロックスコープはないので)
51 | 3. いずれにせよ変数の宣言は、
52 | スコープの先頭に[巻き上げ](http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html)られます。
53 |
54 | ```
55 | function foo () {
56 | var bar = 1; // 良い
57 |
58 | if (true) {
59 | var baz = 2; // 悪い; "baz" は前に宣言しましょう
60 | }
61 | }
62 | ```
63 |
64 | ### 複数の変数の宣言
65 |
66 | 複数の変数を生成する時には一つの `var ` 宣言を使います。それは読みやすいからです。
67 | Sencha は各変数の割り当てを新しい行で宣言することを推奨します。
68 | 値を割り当てない変数は最後に、同じ行に書きます。
69 | 現在のスコープでのその変数の初期状態についてコードを読んでいる人にとって、しかくてきなヒントを提供します。
70 |
71 | // 悪い
72 | var foo = 1;
73 | var bar = 2;
74 | var baz;
75 | var fuz;
76 |
77 | // 良い
78 | var foo = 1,
79 | bar = 2,
80 | baz, fuz;
81 |
82 | ### オブジェクトのプロパティ
83 |
84 | [オブジェクトのプロパティにアクセス](http://stackoverflow.com/questions/4968406/javascript-property-access-dot-notation-vs-brackets)する際、Sencha は、ブラケット記述よりもドット記述を使うことを選びます。その方が一般的に読みやすくより簡単に圧縮できるからです。
85 |
86 | var myObject = {
87 | foo: 'bar'
88 | };
89 |
90 | // 動作するが、好ましくない
91 | myObject['foo'];
92 |
93 | // 好ましい
94 | myObject.foo;
95 |
96 | ブラケット表記によってドット表記で使うことができない文字でプロパティを宣言することができる点に留意してください。
97 |
98 | myObject['~foo'] = true; // うまく動作します
99 | myObject.~foo = true; // エラーが発生します
100 |
101 | クロックフォードなどはブラケット表記を推奨しますが、できるだけコード内で一貫しているようにしましょう。
102 |
103 | 最後に、ブラケット記法は、オブジェクトのプロパティに変数を使ってアクセスするときに非常に便利です。
104 |
105 | var prop = 'foo';
106 | alert(myObject[prop]);
107 |
108 | ### デフォルト値
109 |
110 | また、多くの場合、デフォルト値を定義することはよい方法であると考えられます。
111 |
112 | 単純なシチュエーションでは、`||` を使ってデフォルト値を設定できます。
113 | 左側の値が falsy だった場合、右側の値が使われます。
114 |
115 | function init (config) {
116 | this.hidden = config.hidden || false;
117 | }
118 |
119 | より複雑なシチュエーションでは、バリデーションを実行する、条件式やユーティリティ メソッドを使うのがいいでしょう。
120 |
121 | function init (config) {
122 | // 条件分岐を使う
123 | this.total = (config.count > 10) ? config.count : 10;
124 |
125 | // コンフィグから全てのプロパティをコピーし
126 | // デフォルト値を設定するユーティリティ メソッドを使う
127 | Ext.apply(this, config, {
128 | hidden : false
129 | });
130 | }
131 |
132 | ## 配列リテラル
133 |
134 | ほとんどの場合、新たに配列を生成する場合は、大括弧記法を使います。
135 |
136 | // 悪い
137 | var stuff = new Array();
138 |
139 | // 良い
140 | var stuff = [];
141 |
142 | メンバーが連続した整数であるときに配列を使います。
143 | メンバー名が、任意の文字列や名前である連想配列 (つまり、ディクショナリ) は作ってはいけません。
144 | この場合にはかわりにオブジェクトを生成しましょう。
145 |
146 | // 悪い
147 | var stuff = [];
148 | stuff['foo'] = 'bar';
149 | stuff[0]; // undefined!
150 |
151 | // 良い
152 | var stuff = [ 'bar' ];
153 | stuff[0]; // 'bar'
154 |
155 | ある場合には、
156 | [パフォーマンスの理由で](http://www.slideshare.net/doris1/oscon-developing-high-performance-websites-and-modern-apps-with-javascript-and-html5faster-siteandappformeetupforoscon)
157 | 次元を固定した宣言がよい場合があります。
158 |
159 | この場合には、`new Array(length)` 表記を代わりに使いますが、これには多くの影響があります。
160 |
161 | ## デバッグ ステートメント
162 |
163 | `console.log()` や `debugger` などのデバッグ ステートメントは、決して標準の製品環境にいれて出荷してはなりません。
164 |
165 | よりよいアプローチは、簡単に無効にできるようにこれらのサービスを焼くことです。
166 |
167 | // 悪い
168 | function foo () {
169 | console.log('inside the foo() method');
170 | return true;
171 | }
172 |
173 | // 良い
174 | function foo () {
175 | // logger() は開発環境でのみステートメントを出力する
176 | MyApp.util.logger('inside the foo() method');
177 | return true;
178 | }
179 |
180 | Sencha Cmd を使っている Sencha アプリケーションでは、コードの一部が開発時のみに動作するようにする機能があります。
181 | Sencha Cmd は、製品版ビルドでの最適化の際にこの部分を排除します。
182 |
183 | function foo() {
184 | //
185 | console.log('inside the foo() method');
186 | //
187 | return true;
188 | }
189 |
190 | ## 三項演算子
191 |
192 | 三項演算子は、明確な条件では良いが、複雑な条件では使わない方が良い。
193 |
194 | // 悪い
195 | var value = a && b ? 11 : a ? 10 : b ? 1 : 0;
196 |
197 | // 良い
198 | var value = isSimple ? 11 : 1;
199 |
200 | 三項演算子はネストしてはいけません。それは単に混乱を招くだけだからです。
201 |
202 | **経験則:**
203 | 三項演算子を使うかどうか自信が持てない場合は、デフォルトでは `if/else` 構文を使うようにしましょう。
204 |
205 | しかし、三項演算子において、式に括弧を使うと、他の演算子との関連がはっきりします。
206 | 例えば、
207 |
208 | // 悪い
209 | var value = x || y ? z : a + b;
210 |
211 | // 良い
212 | var value = (x || y) ? z : (a + b);
213 |
214 | ## 正規表現式
215 |
216 | > *"問題があってその解決に RegEx を使う? それは二つ目の問題を抱えることだ。"* (詠み人知らず)
217 |
218 | 正規表現式は非常にパワフルですが、混乱の元になり得ます -- ですからそれらの保守性を高めることの優先度は高くなります。
219 |
220 | 正規表現式をインラインで使ってはいけません。読みやすさと[パフォーマンス](http://jsperf.com/caching-regex-objects/15)のためにいったん変数に保存し、つねにその用途を説明するコメントを書きましょう。
221 |
222 | // 悪い
223 | var hasNumbers = /\d+/.test(value);
224 |
225 | // 良い
226 | var numberTest = /\d+/, //一つ以上の数字が含まれる
227 | hasNumbers = numberTest.test(value);
228 |
229 | パフォーマンスに関しては、正規表現式のリテラルをより永続的な方法にキャッシュすることです。
230 | そうすると、関数が実行される度に再コンパイルされません。
231 |
232 | // 悪い
233 | function hasNumbers (value) {
234 | var numberTest = /\d+/; //関数が呼び出される度に再定義される
235 |
236 | return numberTest.test(value);
237 | }
238 |
239 | // 良い
240 | Ext.define('MyApp.util.RegEx', {
241 | // 一度だけ定義される
242 | numbersRe: /\d+/,
243 |
244 | hasNumbers: function (value) {
245 | return this.numbersRe.test(value);
246 | }
247 | });
248 |
249 | ## 文字列
250 |
251 | 文字列に定義における、シングル クオート/ダブル クォートに一貫したアプローチを取りましょう。
252 | そうするとコードが読みやすく、検索しやすくなります。
253 |
254 | // 悪い
255 | var stringA = 'A', // シングル クォート
256 | stringB = "B"; // ダブル クォート
257 |
258 | // 良い
259 | var stringA = 'A',
260 | stringB = 'B';
261 |
262 | 時に、文字列が長すぎる (例えば 80文字以上になる) 場合に、読みやすくするためだけにそれをいくつかの行に分割しなければならないことがあります。
263 |
264 | // 悪い
265 | var stringA = 'Who lives in a pineapple under the sea? Sponge Bob Square Pants! Absorbent and yellow and porous is he!';
266 |
267 | // 良い
268 | var stringA = 'Who lives in a pineapple under the sea? ' +
269 | 'Sponge Bob Square Pants! ' +
270 | 'Absorbent and yellow and porous is he!';
271 |
272 | **注**: Sencha Cmdでは、上記のような文字の結合を、一つの文字列に変換することで、出力するコードを最適化しています。
273 |
274 | ## メソッドチェーン
275 |
276 | クロックフォードが *JavaScript: The Good Parts* で論じたように、メソッドチェーン (または彼が呼ぶように「カスケード」) を使うと、一つの命令で同じオブジェクトの多くのメソッドを順番に呼び出すことができます。
277 | これらのメソッドは単純に `this` を返すことでチェーンを継続できます。
278 |
279 | // 擬似コード
280 | getElement('myDiv').width(100).height(100).color('red') // のような
281 |
282 | Sencha はこのパターンについてはいくつかの注意を喚起します。
283 | メソッドチェーンの長さが、大きなコードベースの中で時間と共にスパゲッティコードに変わることがあり、これらのコールスタックをデバッグする際には非常に混乱することがあります。
284 |
285 | 多くの場合は、この振る舞いの多くをユーティリティ メソッドの中に抽象化する (そして複数の場所で再利用する) ことで、コードの長期間の保守性を改善することができます。
286 |
--------------------------------------------------------------------------------
/ja/Preventing_JavaScript_Errors.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | #JavaScript エラーを回避する
6 |
7 | [防御的プログラミング](http://en.wikipedia.org/wiki/Defensive_programming)
8 | は、よくある問題が発生する可能性を減らすよう努めるソフトウェア構築アプローチです。
9 | JavaScript 構文は、おかしな動きをしたり微妙な動きをする場合があるので、防御的プログラミング思考法を採用することで、大きなコードベースでの多くの実行時エラーを防ぐことができます。
10 |
11 | - [Lintをかける](#Removing_Lint)
12 | - [セミコロンを使う](#Semicolons)
13 | - [末尾のカンマ](#Trailing_Commas)
14 | - [中括弧とブロック](#Brackets_Blocks)
15 | - [比較演算子](#Equality)
16 | - [プロトタイプ](#Prototypes)
17 | - [関数](#Functions)
18 |
19 | ## Lintをかける
20 |
21 | JavaScript の「lint」ツールはソースコードを読んで、よくあるミスを特定します。例えば関数内の複数の `var` 指令や、文法エラーなどです。
22 | これらのミスは不要なものと見なされ、削除するか再構成することになります。
23 |
24 | 開発中には JSLint、ESLint、JSHit などのツールを使うことが常に推奨されます。
25 | ポピュラーな多くの IDE では、これらのツールと直接的に統合されています。
26 |
27 | しかし、これらのツールはテストやビルドプロセスの自動化の一部として考えなければ鳴りません。
28 | IDE 統合は、エラーについてだけ開発者に警告します。
29 | 問題を解決しなければならないわけではありません。そして、リポジトリに悪いコードがコミットされることを防ぐわけではありません。
30 |
31 | ## セミコロンを使う
32 |
33 | 自動的なセミコロン挿入 (Automatic Semicolon Insertion:ASI) は機能ではありません。
34 | [これに頼らないようにしましょう。](http://benalman.com/news/2013/01/advice-javascript-semicolon-haters/)
35 |
36 | クロックフォードは、単純なものであっても全ての命令の最後にはセミコロンをつけることを推奨しています。
37 | そうするとあらゆる式が命令として使われ、トリッキーなエラーから守られるからです。さらに悪いことに、これらのエラーは開発時には問題がないかも知れませんが、出荷用に圧縮したコードで問題が起こることがあり、その場合は、さらにデバッグは困難になるでしょう。
38 |
39 | // 悪い
40 | var a = obj
41 | [a].forEach(logProp);
42 | // セミコロンがないおかげで次の様な動作をすることになります
43 | // var a = obj[a].forEach(logProp)
44 |
45 | // 良い
46 | var a = obj;
47 | [a].forEach(logProp); // this works fine
48 |
49 |
50 | // 悪い
51 | var example = function () {
52 | // 行が変わったので、"undefined" が返されます
53 | return
54 | {
55 | foo: 123
56 | };
57 | };
58 |
59 | // 良い
60 | var example = function () {
61 | return {
62 | foo: 123
63 | };
64 | };
65 |
66 | ## 末尾のカンマ
67 |
68 | 末尾のカンマは、おそらく他の何よりも JavaScript 開発において、長年の頭痛の元でした。
69 |
70 | var myObject = {
71 | foo : 1,
72 | bar : 2, // 末尾のカンマ
73 | };
74 |
75 | var myArray = [ 1, 2, 3, ]; // 末尾のカンマ
76 |
77 | 現在の ECMAScript 5 仕様では、オブジェクトリテラルや配列リテラルでの末尾のカンマを許可していますが、古いブラウザー (特に IE 9より前) では、予期しない挙動に出会います。オブジェクトでの末尾のカンマはランタイムエラーになり、配列リテラルの末尾のカンマは、Array.length の戻り値が不正確な値になり、配列の項目が有効な値だと想定される場合でもランタイムエラーになることがあります。従って、ベストプラクティスとしては、Sencha では開発者にこれらを使うことを禁じています。
78 |
79 | これに関連して、開発者の中にはこの問題を回避するために、カンマを先頭につけることをします。
80 | Sencha はその解決法が問題を適切に解決するとは思えません。コードの読みやすさを下げるものだと信じています。
81 |
82 | ## 中括弧とブロック
83 |
84 | どんな種類のコードブロックを作る時でも常に中括弧を使います。
85 | 全てのブロック、たとえそれが1行だったとしても、混乱や予想外の動きが実行される可能性を避け、またASI(\*)と括弧なしブロックの組み合わせに起因する複雑なバグをデバッグする苦労を回避するためにも、中括弧で囲むべきです。
86 |
87 | // 悪い
88 | if (foobar) doSomething();
89 |
90 | // 良い
91 | if (foobar) {
92 | doSomething();
93 | }
94 |
95 | \*訳注 ... 自動セミコロン挿入(Automatic Semicolon Insertion)の略。
96 |
97 | 多くの場合に、
98 | [ガード条件](http://refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html)
99 | を使うことは、「通常の」実行パスへの例外を強調できるので、よい方法です。
100 |
101 | // 悪い
102 | function getPayAmount () {
103 | var result;
104 |
105 | if (_isDead) { result = deadAmount(); }
106 | else {
107 | if (_isSeparated) { result = separatedAmount(); }
108 | else {
109 | if (_isRetired) { result = retiredAmount(); }
110 | else { result = normalPayAmount(); }
111 | };
112 | }
113 |
114 | return result;
115 | };
116 |
117 |
118 | // 良い
119 | function getPayAmount() {
120 | if (_isDead) {
121 | return deadAmount();
122 | }
123 | if (_isSeparated) {
124 | return separatedAmount();
125 | }
126 | if (_isRetired) {
127 | return retiredAmount();
128 | }
129 |
130 | return normalPayAmount();
131 | };
132 |
133 | ## 比較演算子
134 |
135 | 特別な理由が無い限り、`==` や `!=` オペレータではなく、`===` や `!==` を使いましょう。
136 |
137 | 「厳密な比較演算子」を使うことで、正確に値を比較でき、変数の型も比較されます。
138 |
139 | // 悪い
140 | var result = (0 == false); //returns TRUE
141 |
142 | // 良い
143 | var result = (0 === false); //returns FALSE
144 |
145 | 厳密ではない比較演算子 (`==` や `!=`) は、
146 | 同じ型に[オペランドをキャストしようとし](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)、
147 | 予期しない truthy/falsy な値を返すことがあります。
148 |
149 | 同じ問題が、if ステートメントの中で[ネイティブの型を比較する](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) 際にも存在します。
150 |
151 | function compare (val) {
152 | return val ? true : false;
153 | }
154 |
155 | compare({}); // true となる
156 | compare([]); // Array は Object なので true となる
157 |
158 | compare(undefined); // false となる
159 | compare(null); // false となる
160 |
161 | compare(true); // true となる
162 | compare(false); // false となる
163 |
164 | compare(0); // +0, -0 false となる
165 | compare(NaN); // false となる
166 | compare(1); // その他の全ての正の値は true となる
167 | compare(-1); // その他の全ての負の値は true となる
168 |
169 | compare(''); // 空文字列は false となる
170 | compare('foo'); // 他の文字列は true となる
171 |
172 | 簡単に言うと、厳密な比較を用いない場合には、変数を比較する際には非常に注意する必要があるということです。
173 |
174 | しかし、直接的な比較をしないで truthy/falsy な値を使うとよい状況もあります。
175 | しかし、もう一度いいますが、開発者は期待される値について慎重であるべきです。
176 |
177 |
178 | if (!disabled) {
179 | // ...
180 | }
181 |
182 | // または
183 | if (enabled) {
184 | // ...
185 | }
186 |
187 | ## プロトタイプ
188 |
189 | JavaScript はプロトタイプベースの言語です -- すべてのオブジェクトは他のオブジェクトを直接的に継承し、フォーマルな「クラス」は存在しません。
190 | プロトタイプ的な継承は概念上はクラス的な継承と似ていますが、クロックフォードは
191 | 「JavaScript はそのプロトタイプ性質について混乱している、なぜならプロトタイプ機構はなんとなく古典的に見える複雑な文法的な事柄によって、プロトタイプ・メカニズムがわかりにくくなっているからだ」
192 | と指摘しています。
193 |
194 | 簡単に言うと、プロトタイプ型の継承のニュアンスを理解することが、エラーを防ぐキーになるということです。
195 |
196 | ### ネイティブのプロトタイプ
197 |
198 | ネイティブのプロトタイプをハックすることはしてはいけません。
199 | [名前の衝突や、互換性のない実装の可能性を](http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/)
200 | を増大させ、必然的に見つけにくいバグに悩まされることに鳴ります。
201 |
202 | 代わりに、お望みの動作を実装するためのユーティリティクラスやメソッドを生成します。
203 |
204 | // 悪い
205 | Array.prototype.each = function (functionToCall) {
206 | //配列の要素をループする
207 | };
208 |
209 | // 良い
210 | Ext.define('Ext.Array', {
211 | singleton: true,
212 |
213 | each: function(arrayToIterate, functionToCall) {
214 | //配列の要素をループする
215 | }
216 | }};
217 |
218 | 注: 場合によっては、ネイティブのプロトタイプをポリフィルすることは、古いブラウザに標準の動作を追加する時には使ってもいいでしょう。
219 | 例えば、Ext JS 5 は、`Function.bind()` を IE8 にポリフィルしています。
220 |
221 | ## 関数
222 |
223 | ### 関数の巻き上げ
224 |
225 | JavaScript の関数を定義する際には、[巻き上げ](http://elegantcode.com/2011/03/24/basic-javascript-part-12-function-hoisting/)に注意しましょう。
226 |
227 | 関数定義は、パース時 (ブラウザが最初にコードをダウンロードした際) に評価されます。
228 |
229 | // 関数宣言 (好ましい)
230 | function sum (x, y) {
231 | return x + y;
232 | }
233 |
234 | なぜなら、宣言は関数がいつ定義されたかに関係なく、パース時にスコープの先頭に巻き上げられます。
235 |
236 | sum(1,2); // 3 を返す
237 |
238 | // 関数宣言 (好ましい)
239 | function sum (x, y) {
240 | return x + y;
241 | }
242 |
243 | 関数式は、他の変数の割り当てと同様、実行時 (コールスタックが実際にコードのその行に来たとき) に評価されます。
244 |
245 | // 関数式
246 | var sum = function (x, y) {
247 | return x + y;
248 | };
249 |
250 | 関数式は、パース時に巻き上げられないので、関数が定義される時が問題になります。
251 |
252 | sum(1,2); //"undefined is not a function" エラーが発生する
253 |
254 | // 関数式
255 | var sum = function (x, y) {
256 | return x + y;
257 | };
258 |
259 | 関数式の利用は、変数名を短いものに安全に置き換えることができるため、より良い圧縮に繋がります。
260 | これは、関数宣言の名前だけに典型的に適用される動きではありません。
261 |
262 | ### 無名関数
263 |
264 | 無名関数はとても便利ですが、貧弱な構成のコードでは、簡単に[メモリリーク](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript#Memory_leaks)を引き起こします。
265 | 次のサンプルを検討してください。
266 |
267 | function addHandler () {
268 | var el = document.getElementById('el');
269 |
270 | el.addEventListener(
271 | 'click',
272 | function() { // 無名関数
273 | el.style.backgroundColor = 'red';
274 | }
275 | );
276 | }
277 |
278 | ここでは、無名関数を使うことによって二つの問題が発生しています。
279 |
280 | 1. click ハンドラー関数には名前付きの参照がないため、[removeEventListener()](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.removeEventListener) で削除することができません。
281 | 2. `el` への参照が無意識で内側の関数でクロージャーを形成しています。
282 | そしてそのためガーベージコレクションすることができません。
283 | これは、JavaScript (関数) と DOM (`el`) の間で循環参照を生成しています。
284 |
285 | 最初の問題を除去するには、イベントリスナーを追加する時には常に、名前付きの関数を使うことです。
286 |
287 | 二つ目の問題を除去するには、メモリリークを避け、ガーベージコレクションをさせることです。
288 |
289 | function clickHandler () {
290 | this.style.backgroundColor = 'red';
291 | }
292 |
293 | function addHandler () {
294 | var el = document.getElementById('el');
295 | el.addEventListener('click', clickHandler);
296 | }
297 |
298 | 最後に: 無名関数パターンによるリスクは、Sencha クラスシステムのパラダイムに従うことで緩和できます。
299 | フレームワークは、多くのスコープやバインドを管理します。
300 |
--------------------------------------------------------------------------------
/Maintainable_JavaScript.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Writing Maintainable JavaScript
6 |
7 | In his book *Facts and Fallacies of Software Engineering*, Robert Glass discusses how as much as 80% of the total cost
8 | of software over its lifetime comes from maintenance tasks. This isn't just fixing bugs; in most cases, "maintenance"
9 | actually involves adding new functionality to existing applications.
10 |
11 | The implications here are clear: if developers spend the vast majority of their time maintaining applications,
12 | then the code should always be written to make that process easier.
13 |
14 | Sencha recommends prioritizing the following points to help reduce the long-term friction involved in maintaining
15 | a large codebase:
16 |
17 | - [One Class Per File](#One_Class_Per_File)
18 | - [Declaring Variables](#Declaring_Variables)
19 | - [Array Literals](#Array_Literals)
20 | - [Debugging Statements](#Debugging_Statements)
21 | - [Ternary Operators](#Ternary_Operators)
22 | - [Regular Expressions](#Regular_Expressions)
23 | - [Strings](#Strings)
24 | - [Method Chains](#Method_Chains)
25 |
26 | ## One Class Per File
27 |
28 | Sencha strongly encourages the practice of coding only one class per file. Doing so makes maintaining and debugging
29 | applications easier, because the developer knows exactly where to find their code.
30 |
31 | In addition, Sencha recommends using a consistent approach to naming and organizing your files. The file name should
32 | match the class name defined within, and the physical file location should match the class' namespace.
33 |
34 | For example, the class `Foo.bar.Baz` might be defined in `Baz.js`. Per the full namespace, the file might be located
35 | at `/src/Foo/bar/Baz.js`.
36 |
37 | ## Declaring Variables
38 |
39 | Sencha typically follows Crockford's advice to declare variables at the top of their scope because:
40 |
41 | 1. finding variable declarations becomes easier
42 | 2. it makes the scope of the variables clear (as JavaScript does not have block scope)
43 | 3. variable declarations are [hoisted](http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html) to the top of their scope anyways
44 |
45 | ```
46 | function foo () {
47 | var bar = 1; // good
48 |
49 | if (true) {
50 | var baz = 2; // bad; "baz" should be declared above
51 | }
52 | }
53 | ```
54 |
55 | ### Declaring Multiple Variables
56 |
57 | Use one `var` declaration when creating multiple variables because it is easier to read. Sencha recommends declaring
58 | each variable assignment on a new line; declare unassigned variables last, and these can be on the same line.
59 | This provides a visual cue to the person reading your code about the initial state of the variables within the current scope.
60 |
61 | // bad
62 | var foo = 1;
63 | var bar = 2;
64 | var baz;
65 | var fuz;
66 |
67 | // good
68 | var foo = 1,
69 | bar = 2,
70 | baz, fuz;
71 |
72 | ### Object Properties
73 |
74 | When [accessing object properties](http://stackoverflow.com/questions/4968406/javascript-property-access-dot-notation-vs-brackets),
75 | Sencha prefers to use dot notation rather than bracket notation because it is typically easier to read and is
76 | more easily compressed.
77 |
78 | var myObject = {
79 | foo: 'bar'
80 | };
81 |
82 | // works, but not preferred
83 | myObject['foo'];
84 |
85 | // preferred
86 | myObject.foo;
87 |
88 | It should be noted that bracket notation does allow you to declare properties with characters that can't be used
89 | in dot notation.
90 |
91 | myObject['~foo'] = true; // works just fine
92 | myObject.~foo = true; // will throw an error
93 |
94 | While Crockford and others recommend against bracket notation, the takeaway here is to be as consistent in your
95 | code as possible.
96 |
97 | Finally, bracket notation can be very useful when using a variable to access object properties:
98 |
99 | var prop = 'foo';
100 | alert(myObject[prop]);
101 |
102 | ### Default Values
103 |
104 | It is also considered good practice to define default values in many cases.
105 |
106 | For simple situations, you can use `||` to define default values. If the left-hand value is falsy then the right-hand
107 | value will be used.
108 |
109 | function init (config) {
110 | this.hidden = config.hidden || false;
111 | }
112 |
113 | In more complex scenarios, it may make sense to use conditional expressions or utility methods to perform the validations:
114 |
115 | function init (config) {
116 | // using a conditional
117 | this.total = (config.count > 10) ? config.count : 10;
118 |
119 | // using a utility method
120 | // to copy all properties from config but also provide default values
121 | Ext.apply(this, config, {
122 | hidden : false
123 | });
124 | }
125 |
126 | ## Array Literals
127 |
128 | In most cases, you should create new arrays by using the square bracketed notation:
129 |
130 | // bad
131 | var stuff = new Array();
132 |
133 | // good
134 | var stuff = [];
135 |
136 | Use arrays when the member names will be sequential integers; do not create associative arrays (i.e. dictionaries)
137 | where the member names are arbitrary strings or names -- create an object for those cases instead.
138 |
139 | // bad
140 | var stuff = [];
141 | stuff['foo'] = 'bar';
142 | stuff[0]; // undefined!
143 |
144 | // good
145 | var stuff = [ 'bar' ];
146 | stuff[0]; // 'bar'
147 |
148 | Note: some cases exist where declaring a fixed-dimension array for
149 | [performance reasons](http://www.slideshare.net/doris1/oscon-developing-high-performance-websites-and-modern-apps-with-javascript-and-html5faster-siteandappformeetupforoscon)
150 | might make sense. In those cases it's fine to use the `new Array(length)` notation instead, but there are many
151 | implications to doing so.
152 |
153 | ## Debugging Statements
154 |
155 | Debugging statements like `console.log()` and `debugger` should never be shipped into standard production environments.
156 | A better approach is to bake these statements into a service that can easily be disabled in production.
157 |
158 | // bad
159 | function foo () {
160 | console.log('inside the foo() method');
161 | return true;
162 | }
163 |
164 | // good
165 | function foo () {
166 | // where logger() only outputs statements in development
167 | MyApp.util.logger('inside the foo() method');
168 | return true;
169 | }
170 |
171 | Sencha applications utilizing Sencha Cmd also have the ability to mark sections of code as being run only in
172 | development; Sencha Cmd will then strip out these sections during the optimization process for production builds.
173 |
174 | function foo () {
175 | //
176 | console.log('inside the foo() method');
177 | //
178 | return true;
179 | }
180 |
181 | ## Ternary Operators
182 |
183 | Ternary operators are fine for clear-cut conditionals, but unacceptable for confusing choices.
184 |
185 | // bad
186 | var value = a && b ? 11 : a ? 10 : b ? 1 : 0;
187 |
188 | // good
189 | var value = isSimple ? 11 : 1;
190 |
191 | Ternary expressions should never be nested because they just add to the confusion.
192 |
193 | **Rule of thumb:** If you are unsure whether-or-not you should be using a ternary expression, always default to
194 | using an `if/else` statement instead.
195 |
196 | However, parenthesis can be very helpful to express more clearly the binding of other operators when combined with
197 | ternary operators. For example:
198 |
199 | // bad
200 | var value = x || y ? z : a + b;
201 |
202 | // good
203 | var value = (x || y) ? z : (a + b);
204 |
205 | ## Regular Expressions
206 |
207 | > *"Have a problem and you think RegEx is the solution? Now you have 2 problems."* (anonymous joke)
208 |
209 | Regular expressions are very powerful but can be confusing -- therefore keeping them maintainable is a high priority.
210 |
211 | Don't inline regular expressions; store them in a variable to improve readability and
212 | [performance](http://jsperf.com/caching-regex-objects/15), and always add comments to explain their purpose.
213 |
214 | // bad
215 | var hasNumbers = /\d+/.test(value);
216 |
217 | // good
218 | var numberTest = /\d+/, //contains one or more numbers
219 | hasNumbers = numberTest.test(value);
220 |
221 | When it comes to performance, a better practice is to cache literal Regular Expressions in a more permanent way -- so
222 | that they are not re-compiled each time a function is run.
223 |
224 | // bad
225 | function hasNumbers (value) {
226 | var numberTest = /\d+/; //gets re-defined on each function call
227 |
228 | return numberTest.test(value);
229 | }
230 |
231 | // good
232 | Ext.define('MyApp.util.RegEx', {
233 | // defined only once
234 | numbersRe : /\d+/,
235 |
236 | hasNumbers: function (value) {
237 | return this.numbersRe.test(value);
238 | }
239 | });
240 |
241 | ## Strings
242 |
243 | Pick a consistent approach to defining strings: single or double quotes. This will make the code easier to read
244 | and easier to search.
245 |
246 | // bad
247 | var stringA = 'A', // single quotes
248 | stringB = "B"; // double quotes
249 |
250 | // good
251 | var stringA = 'A',
252 | stringB = 'B';
253 |
254 | Sometimes a string must be broken across several lines if it’s too long (e.g. >80 characters) to simply improve
255 | readability.
256 |
257 | // bad
258 | var stringA = 'Who lives in a pineapple under the sea? Sponge Bob Square Pants! Absorbent and yellow and porous is he!';
259 |
260 | // good
261 | var stringA = 'Who lives in a pineapple under the sea? ' +
262 | 'Sponge Bob Square Pants! ' +
263 | 'Absorbent and yellow and porous is he!';
264 |
265 | **Note**: Sencha Cmd optimizes literal string operations like the above and generates a single string literal
266 | in the output code.
267 |
268 | ## Method Chains
269 |
270 | As Crockford discusses in *JavaScript: The Good Parts*, method chains (or "cascades" as he calls them) allow us
271 | to call many methods on the same object in sequence during a single statement. These methods simply return `this` to
272 | allow the chain to continue:
273 |
274 | //pseudocode
275 | getElement('myDiv').width(100).height(100).color('red') // etc.
276 |
277 | Sencha urges some caution with this pattern as the lengthy method chains can turn into spaghetti code over time
278 | in large codebases, and debugging these call stacks can be very confusing. In many cases, abstracting much of this
279 | behavior into a utility method (then re-used in multiple places) will improve the long-term maintainability of your code.
280 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/Preventing_JavaScript_Errors.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Preventing JavaScript Errors
6 |
7 | [Defensive Programming](http://en.wikipedia.org/wiki/Defensive_programming) is an approach to building software which
8 | strives to reduce the likelihood of common problems. Because JavaScript syntax contains many gotchas and edge cases,
9 | adopting a defensive programming mindset can help to prevent many runtime errors in large codebases.
10 |
11 | - [Removing Lint](#Removing_Lint)
12 | - [Using Semicolons](#Semicolons)
13 | - [Trailing Commas](#Trailing_Commas)
14 | - [Brackets and Blocks](#Brackets_Blocks)
15 | - [Equality](#Equality)
16 | - [Prototypes](#Prototypes)
17 | - [Functions](#Functions)
18 |
19 | ## Removing Lint
20 |
21 | JavaScript "lint" tools read your source code to help identify common mistakes -- things as subjective as multiple
22 | `var` statements in a function, or as objective as flagrant syntax errors. These mistakes are considered "lint"
23 | and should be removed or restructured.
24 |
25 | Using tools such as JSLint, ESLint, JSHint, etc is always recommended during development. Many popular IDEs even have
26 | direct integration with these tools.
27 |
28 | However, you should also consider making these tools part of your automated testing or build processes. IDE integration
29 | will only warn the developer about errors - it does not force them to correct problems, and it will not prevent the
30 | bad code from being committed to your repo.
31 |
32 | ## Using Semicolons
33 |
34 | Automatic Semicolon Insertion (ASI) is not a feature. [Don't rely on it.](http://benalman.com/news/2013/01/advice-javascript-semicolon-haters/)
35 |
36 | Crockford recommends putting a semicolon at the end of every simple statement because JavaScript allows any expression
37 | to be used as a statement, which can mask some tricky errors. What is worse, these errors may not be apparent in the development process but could appear in the minified production code instead, and that would make them even harder to debug.
38 |
39 | // bad
40 | var a = obj
41 | [a].forEach(logProp);
42 | // Because a semicolon isn't used that code behaves like this:
43 | // var a = obj[a].forEach(logProp)
44 |
45 | // good
46 | var a = obj;
47 | [a].forEach(logProp); // this works fine
48 |
49 |
50 | // bad
51 | var example = function () {
52 | // because of the line break, ASI returns "undefined"
53 | return
54 | {
55 | foo: 123
56 | };
57 | };
58 |
59 | // good
60 | var example = function () {
61 | return {
62 | foo: 123
63 | };
64 | };
65 |
66 | ## Trailing Commas
67 |
68 | Trailing commas have caused more headaches in JavaScript development over the years than perhaps anything else.
69 |
70 | var myObject = {
71 | foo : 1,
72 | bar : 2, // trailing comma
73 | };
74 |
75 | var myArray = [ 1, 2, 3, ]; // trailing comma
76 |
77 | Although the current ECMAScript 5 specification allows for trailing commas in Object and Array literals, older
78 | browsers (particularly IE <9) encounter unexpected behavior: trailing commas in object literals would throw runtime
79 | errors, while trailing commas in array literals would result in an extra `undefined` item at the end of the array. This would not only return inaccurate results for Array.length but also may cause runtime exceptions if your code assumes that array items are valid objects.
80 |
81 | Therefore, as a best practice, Sencha discourages developers from using them.
82 |
83 | On a related note, some developers prefer to use leading commas to avoid this problem. Sencha doesn't feel that
84 | solution adequately solves the issue, and furthermore we believe it reduces the readability of the code.
85 |
86 | ## Brackets and Blocks
87 |
88 | Always use brackets when creating code blocks of any kind. Every block, even if it is only one line, needs to have
89 | its own curly braces in order to avoid confusion and prevent the possibility of hard to track bugs that may result from the combination of braceless block with ASI which could produce some very unexpected code.
90 |
91 | // bad
92 | if (foobar) doSomething();
93 |
94 | // good
95 | if (foobar) {
96 | doSomething();
97 | }
98 |
99 | In many cases, the use of [guard clauses](http://refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html)
100 | makes good sense as they highlight exceptions to the "normal" execution path:
101 |
102 | // bad
103 | function getPayAmount () {
104 | var result;
105 |
106 | if (_isDead) { result = deadAmount(); }
107 | else {
108 | if (_isSeparated) { result = separatedAmount(); }
109 | else {
110 | if (_isRetired) { result = retiredAmount(); }
111 | else { result = normalPayAmount(); }
112 | };
113 | }
114 |
115 | return result;
116 | };
117 |
118 |
119 | // good
120 | function getPayAmount () {
121 | if (_isDead) {
122 | return deadAmount();
123 | }
124 | if (_isSeparated) {
125 | return separatedAmount();
126 | }
127 | if (_isRetired) {
128 | return retiredAmount();
129 | }
130 |
131 | return normalPayAmount();
132 | };
133 |
134 | ## Equality
135 |
136 | Always favor the `===` and `!==` operators over `==` and `!=` unless you have specific reasons not to.
137 |
138 | By using the "strict equality operators", we can accurately compare the value and type of the variables being compared.
139 |
140 | // bad
141 | var result = (0 == false); //returns TRUE
142 |
143 | // good
144 | var result = (0 === false); //returns FALSE
145 |
146 | The non-strict equality operators (`==` and `!=`) [will attempt to cast the operands](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
147 | into the same value type, returning truthy or falsy results which may not be expected.
148 |
149 | The same problem exists when [comparing native types](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108)
150 | in an if statement:
151 |
152 | function compare (val) {
153 | return val ? true : false;
154 | }
155 |
156 | compare({}); // evaluates to true
157 | compare([]); // evaluates to true, because Array is an Object
158 |
159 | compare(undefined); // evaluates to false
160 | compare(null); // evaluates to false
161 |
162 | compare(true); // evaluates to true
163 | compare(false); // evaluates to false
164 |
165 | compare(0); // +0, -0 evaluate to false
166 | compare(NaN); // evaluates to false
167 | compare(1); // all other positive numbers evaluate to true
168 | compare(-1); // all other negative numbers evaluate to true
169 |
170 | compare(''); // empty string evaluates to false
171 | compare('foo'); // all other strings evaluate to true
172 |
173 | In short, you need to be very careful when testing the equality of any variables when not using the strict
174 | equality operators!
175 |
176 | However, there are some situations in which using truthy or falsy values without direct comparison are acceptable --
177 | but again, developers should always be cautious about the values they expect.
178 |
179 | if (!disabled) {
180 | // ...
181 | }
182 |
183 | // or
184 | if (enabled) {
185 | // ...
186 | }
187 |
188 | ## Prototypes
189 |
190 | JavaScript is a prototype-based language -- all objects inherit directly from other objects, and formal "classes"
191 | do not exist. Prototypal inheritance is conceptually similar to classical inheritance, but Crockford points out that
192 | "JavaScript is conflicted about its prototypal nature" because "the prototype mechanism is obscured by some
193 | complicated syntactic business that looks vaguely classical".
194 |
195 | In short, understanding the nuances of prototypal inheritance is key to avoiding errors.
196 |
197 | ### Native Prototypes
198 |
199 | Hacking native prototypes should be avoided. It increases the [possibility of naming collisions and incompatible implementations](http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/),
200 | inevitably causing headaches and hard-to-find bugs.
201 |
202 | Instead, create utility classes/methods to implement the desired behavior:
203 |
204 | // bad
205 | Array.prototype.each = function (functionToCall) {
206 | //loop over the items in the array
207 | };
208 |
209 | // good
210 | Ext.define('Ext.Array', {
211 | singleton : true,
212 |
213 | each: function (arrayToIterate, functionToCall) {
214 | //loop over the items in the array
215 | }
216 | }};
217 |
218 | Note: in some situations, polyfilling native prototypes may be acceptable to add standard behavior to older browsers.
219 | For example, Ext JS 5 pollyfills `Function.bind()` in IE8.
220 |
221 | ## Functions
222 |
223 | ### Function Hoisting
224 |
225 | When defining JavaScript functions, beware of [hoisting](http://elegantcode.com/2011/03/24/basic-javascript-part-12-function-hoisting/).
226 |
227 | Function declarations are evaluated at parse-time (when the browser first downloads the code):
228 |
229 | // FUNCTION DECLARATION (preferred)
230 | function sum (x, y) {
231 | return x + y;
232 | }
233 |
234 | Because the declaration is hoisted to the top of its scope at parse-time, it doesn't matter when the function is defined:
235 |
236 | sum(1,2); // returns 3
237 |
238 | // FUNCTION DECLARATION (preferred)
239 | function sum (x, y) {
240 | return x + y;
241 | }
242 |
243 | Function expressions are evaluated at run-time (when the call stack physically hits a line of code), just like any
244 | other variable assignment:
245 |
246 | // FUNCTION EXPRESSION
247 | var sum = function (x, y) {
248 | return x + y;
249 | };
250 |
251 | Because function expressions are NOT hoisted at parse-time, it DOES matter when the function is defined:
252 |
253 | sum(1,2); //throws an error "undefined is not a function"
254 |
255 | // FUNCTION EXPRESSION
256 | var sum = function (x, y) {
257 | return x + y;
258 | };
259 |
260 | Using function expressions can result in better compression because the name can be safely replaced by
261 | a shorter version. This is not typically done for the name in a function declaration.
262 |
263 | ### Anonymous Functions
264 |
265 | Anonymous functions can be very convenient, but poorly constructed code can easily lead to
266 | [memory leaks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript#Memory_leaks).
267 | Consider the following example:
268 |
269 | function addHandler () {
270 | var el = document.getElementById('el');
271 |
272 | el.addEventListener(
273 | 'click',
274 | function () { // anonymous function
275 | el.style.backgroundColor = 'red';
276 | }
277 | );
278 | }
279 |
280 | There are two issues caused by using an anonymous function:
281 |
282 | 1. We don’t have a named reference to the click handler function, so we can’t remove it via [removeEventListener()](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.removeEventListener)
283 | 2. The reference to `el` is inadvertently caught in the closure created for the inner function, and therefore
284 | cannot be garbage collected. This creates a circular reference between JavaScript (the function) and the DOM (`el`).
285 |
286 | To avoid the first problem, always use named functions when adding event listeners to DOM elements.
287 |
288 | To avoid the second problem, carefully craft your scopes to prevent leaks and promote garbage collection:
289 |
290 | function clickHandler () {
291 | this.style.backgroundColor = 'red';
292 | }
293 |
294 | function addHandler () {
295 | var el = document.getElementById('el');
296 | el.addEventListener('click', clickHandler);
297 | }
298 |
299 | One final note: the risks exposed by the anonymous function pattern are often mitigated by following the paradigms
300 | of the Sencha class system, where the framework manages much of this scoping and binding for you.
301 |
--------------------------------------------------------------------------------
/ja/Readable_JavaScript.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # 読みやすいJavaScriptを書く
6 |
7 | 「読みやすい」JavaScriptを書く重要性は、単純に誇張しているのではありません。チームの他のメンバーのためだけでなく、未来の自分のためにも、簡単に概要を掴めるコードを書くようにして下さい。
8 |
9 | 著書「*Facts and Fallacies of Software Engineering*(\*)」で、著者のRobert Glassは「既存の製品の理解」に開発者の時間の約3割が消費されている点を指摘しています。Glassのこの見解はソフトウェア保守サイクルのコンテキストで述べられていますが(「保守」という観点については後ほど改めて議論します)、当社は下記の項目について、首尾一貫して明確な優先順位を付けることをお勧めします。
10 |
11 | - [命名規約](#Naming_Conventions)
12 | - [コメントと文書化](#Comments_Documentation)
13 | - [オーバーライドの文書化](#Documenting_Overrides)
14 | - [インデントや空白](#Spacing_White_Space)
15 | - [行の長さ](#Line_Length)
16 | - [ブロックの長さ](#Block_Length)
17 | - [ファイルの長さ](#File_Length)
18 |
19 | \*訳注 ... ソフトウエア開発 55の真実と10のウソ(日経BP出版センター)
20 |
21 | ## 命名規約
22 |
23 | > *"コンピュータ・サイエンスには2つの難しいものがあります。キャッシュの制御、命名規約、そして境界値のズレに関するエラー"*
24 |
25 | ほとんどの人は人生において幾つかのものにしか名前を付けるという行為を行いません: ペット、子供、または個人的に特別な意味を持った何か。
26 |
27 | 一般的に、名前付けは一度決めると最後まで使われるため、難しい作業だと言えます(例えば、ペットの名前を付け直すことはめったにないでしょう)。しかし、ソフトウェアの開発において、開発者は平均的な人々よりも多くの名前付けをすることになります。
28 |
29 | ソフトウェア開発者は恐らく年に数千の名前を付けることになるでしょう(変数、クラス、アプリケーション等)。それらの名前は、その名前が付けられた目的やコンセプトを示そうとするでしょう。しかしプログラムでは、覚えやすいように名付けられたものだけでなく、たくさんの名前を使うことになります。そのため名前は、他の人が数ヶ月から数年に渡って理解し、修正し、拡張できるよう、分かり易い状態に保たなければなりません。この考え方はしばしば「self-documenting code(自己文書化コード)」と呼ばれます。
30 |
31 | それでは、命名規約を適用した方がよい箇所と、当社がどのようにそれらを扱っているかについて解説します。
32 |
33 | ### 名前空間、クラス、コンストラクタ
34 |
35 | 当社では、最上位の名前空間、クラス、コンストラクタに命名する際は、いつも「タイトル・ケース」を利用しています。
36 |
37 | // "MyClass" はコンストラクタ :: new MyClass();
38 | MyClass = function () {};
39 |
40 | 中間の名前空間は短くした方が良く、説明的な内容で小文字にします。
41 |
42 | // "Foo" は最上位の名前空間
43 | // "bar" は中間レベルの名前空間
44 | // "Baz" はクラス名
45 | Foo.bar.Baz = {};
46 | Ext.data.reader.Json = {};
47 |
48 | ### 関数
49 |
50 | 当社では関数を定義する際は、常に「キャメル・ケース」を利用します。また、クロージャでカプセル化されていないプライベートな関数を命名する際は、先頭にアンダースコア "\_" を付けることをお奨めします。
51 |
52 | // 関数式
53 | var sortSomeStuff = function () {};
54 |
55 | // 関数宣言
56 | function findSomething () {}
57 |
58 | // オブジェクトの関数についても同様の考え方を適用します
59 | var someObject = {
60 | objectMethod: function () {},
61 |
62 | _privateMethod: function () {}
63 | };
64 |
65 | 注: [関数](Preventing_JavaScript_Errors.md#Functions) で、関数式と関数宣言の使用についての詳しい情報を記載しています。
66 |
67 | ### ローカル変数とオブジェクトのプロパティ
68 |
69 | ローカル変数を宣言する際は、常に「var」キーワードを使います。そうしないと、グローバル変数を作成することになり、汚染されたグローバルの変数を避ける必要が出てきます。この問題の詳細は [定数とグローバル変数](#Constants_Global_Vars) のセクションを参照下さい。
70 |
71 | // 悪い例
72 | foo = true;
73 |
74 | // 良い例
75 | var foo = true;
76 |
77 | 当社では、ローカル変数とオブジェクトのプロパティを作成する際は、常に「キャメルケース」を利用しています。また、オブジェクトにプライベートなプロパティを名付ける場合は、先頭にアンダースコア「\_」を付与することをお奨めします。
78 |
79 | // ローカル変数
80 | var fooBar = true;
81 |
82 | // オブジェクトのプロパティ
83 | var someObject = {
84 | someProperty: true,
85 |
86 | _privateProperty: true
87 | };
88 |
89 | 変数は、その目的や機能を明確にするため、意味のある名前を付ける必要があります。(もちろん完結であることも必要です)
90 | 一文字だけの名前は避けましょう。とはいえ、イテレータの変数はその例外にはなります。
91 |
92 | // 悪い例。短過ぎです。説明的ではないですし、数字の1とも誤解しそうです。
93 | var l = group.length;
94 |
95 | // 良くない例。変数名が必要以上に長い。
96 | var mainClassConfigVariableSectionOneRefreshInterval = 5000;
97 |
98 | // 良い例です。名前は完結で、ちゃんと意味も取れます。
99 | var len = group.length;
100 |
101 | // イテレータについては、例外。
102 | var i;
103 | for (i = 0; i < len; i++) {}
104 |
105 | 複数の変数を定義する際は、一つだけの「var」宣言を利用しましょう。その方が読み易いですから。当社では、一行ごとに一つの変数を定義する方法を推奨しています。
106 | また、値を代入しない変数は最後にします。代入のない変数を複数宣言する場合については、一行で済ますこともありますが。
107 |
108 | この方法は、現在のスコープで変数の初期状態がどうなっているのか視覚的に示すことができます。
109 |
110 | // 悪い例
111 | var foo = 1;
112 | var bar = 2;
113 | var baz;
114 | var fuz;
115 |
116 | // 良い例
117 | var foo = 1,
118 | bar = 2,
119 | baz, fuz;
120 |
121 | ### 定数とグローバル変数
122 |
123 | 当社はグローバル変数と定数を宣言する際は、「CONSTANT_CASE」の利用を推奨します。そうすることで、この変数は特別なものであることを視覚的に明確にできます。
124 |
125 | // 悪い例
126 | userID = '12345';
127 |
128 | // 良い例
129 | USER_ID = '12345';
130 |
131 | 我々は企業アプリケーションでは、その代わりに適切な名前空間に配置されたクラスを使うことでのメリットがあると感じています。それはどこで値が定義されたかが常に明白だからです。
132 |
133 | // より良い
134 | MyApp.authentication.User = {
135 | id: '12345'
136 | };
137 |
138 | ### 特別な場合
139 |
140 | このほかの特別な場合も存在します -- 例えば、`this` を参照する名前です。
141 |
142 | 内部的な規則として、Sencha では、クロージャーの中で `this` への参照を保持する必要があるときに `me` という名前を使います。
143 | 全員が賛成しているわけではありませんが -- クリスチャン ジョナサン [a notable example](https://gist.github.com/cjohansen/4135065) -- より素晴らしい点は、コードベース全体で一貫してこれらの特別な場合を管理することです。
144 |
145 | Person.logger = function () {
146 | var me = this; // "me" will be used consistently
147 |
148 | return function () {
149 | console.log(me);
150 | };
151 | };
152 |
153 | もう一つの重要な点は、this はキーワードであり圧縮できないということです。 Sencha フレームワークでは、我々は「4のルール」を守ります。 特定のスコープ内で、this が 4回以上参照されたら、this をローカル変数 me でキャッシュします。そうするとミニファイされるソースをより小さくできます。
154 |
155 | // 悪い
156 | function foo () {
157 | this.x = 1;
158 | this.y = 2;
159 | this.z = 3;
160 | this.u = 4;
161 | }
162 |
163 | // 良い
164 | function foo () {
165 | var me = this;
166 | me.x = 1;
167 | me.y = 2;
168 | me.z = 3;
169 | me.u = 4;
170 | }
171 |
172 | // ミニファイの出力の比較
173 | function f(){this.x=1;this.y=2;this.z=3}
174 | function f(){var e=this;e.x=1;e.y=2;e.z=3}
175 |
176 | function f(){this.x=1;this.y=2;this.z=3;this.u=4;}
177 | function f(){var e=this;e.x=1;e.y=2;e.z=3;e.u=4;} // 4 でより短くなります
178 |
179 | function f(){this.x=1;this.y=2;this.z=3;this.u=4;this.v=5;}
180 | function f(){var e=this;e.x=1;e.y=2;e.z=3;e.u=4;e.v=5;}
181 |
182 | ### 予約語
183 |
184 | 予約語をキーとして使っていけません。 Internet Explorer の古いバージョンで動作しないからです。 予約語の代わりに分かりやすい同義語を使います。
185 |
186 | // 悪い
187 | var model = {
188 | name: 'Foo',
189 | private: true // reserved word!
190 | };
191 |
192 | // 良い
193 | var model = {
194 | name: 'Foo',
195 | hidden: true
196 | };
197 |
198 | 注: 「分かりやすい同義語」は実際の単語にします。
199 |
200 | // 悪い
201 | var car = {
202 | class: 'Ford' // 予約語
203 | };
204 |
205 | // 悪い
206 | var car = {
207 | klass: 'Ford' // お願い。二度とこんなことしないで
208 | };
209 |
210 | // 良い
211 | var car = {
212 | brand: 'Ford'
213 | };
214 |
215 | ## コメントと文書化
216 |
217 | 一般的に言って、良いコードは自己説明的だとされています。 しかしながら、コメントは読みやすいコードにするために二つの重要な役割を果たします。 文書化と意図 (インラインコメントによる) です。
218 |
219 | ### 文書化
220 |
221 | システム全体の文書化は、大きなコードベースを開発する際にきわめて重要です。 [JSDuck](https://github.com/senchalabs/jsduck) のようなツールを使うと、コードベースの API リファレンスを簡単に作ることができます。
222 |
223 | [Sencha](http://docs.sencha.com/extjs/5.0/apidocs/) は、内部的に JSDuck を使っています。 JSDuck は、 JavaDoc スタイルのブロックコメントを追跡します。 [JSDuck wiki](https://github.com/senchalabs/jsduck/wiki) で、詳細をご覧になれます。
224 |
225 | /**
226 | * @class MyApp.foo.Bar
227 | */
228 | MyApp.foo.Bar = function () {
229 | var baz = true;
230 |
231 | return {
232 | /**
233 | * @method
234 | */
235 | utilityMethod: function () {
236 | return baz;
237 | }
238 | };
239 | };
240 |
241 | ### インライン コメント
242 |
243 | 多くの開発者が、コードは「自己文書化」であるべきと感じていて、それによってインライン・コメントはつけるべきでないと感じています。 Sencha は、その思考法の頑固さに必ずしも同意できません。 我々は、コードの意図または目的が完全に明白でないときには、常にコメントをするものだと思っています。しかし、コードそのものは論理的に追いかける際に十分明白であるようにしましょう。
244 |
245 | // 多くの場合、コントローラIDは、その名前と同じです。
246 | // しかし、コントローラに手動でIDが与えられると、そのように
247 | // コレクションの中のキーになります。
248 | // ですから、それを見つけないと、我々は既存のコントローラをループして、
249 | // クラス名を使ってそれを見つけようとします。
250 | if (!controller) {
251 | all = controllers.items;
252 | for (i = 0, len = all.length; i < len; ++i) {
253 | cls = all[i];
254 | className = cls.getModuleClassName();
255 | if (className && className === name) {
256 | controller = cls;
257 | break;
258 | }
259 | }
260 | }
261 |
262 | 正規表現式は、本質的に混乱する記法ですから、常にコメントで説明を書きましょう。
263 |
264 | // ローマ数字の入力に一致する
265 | var romanNums = /^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/;
266 |
267 | コードブロック全体をコメントアウトするのは避けましょう。 それは、用途がなくコードを肥大化させるだけですから。
268 |
269 | // どうして次のコードが製品版に残っているの?
270 | items : [
271 | //{
272 | // xtype : 'booleancolumn',
273 | // width : 5,
274 | // resizable : false,
275 | // defaultWidth : 5,
276 | // sortable : false,
277 | // dataIndex : 'isOwn',
278 | // groupable : false,
279 | // hideable : false,
280 | // lockable : false,
281 | // tdCls : 'indicator',
282 | // falseText : ' ',
283 | // trueText : ' '
284 | //},
285 | //{
286 | // xtype : 'gridcolumn',
287 | // dataIndex : 'key',
288 | // text : 'Binding Key',
289 | // flex : 1
290 | //},
291 | {
292 | xtype : 'templatecolumn',
293 | dataIndex : 'boundTo',
294 | text : 'Bound To',
295 | flex : 1,
296 | tpl : '\\{{boundTo}\\}'
297 | },
298 | {
299 | xtype : 'gridcolumn',
300 | dataIndex : 'value',
301 | text : 'Value',
302 | flex : 1,
303 | renderer : function (value, metaData, record, rowIndex, colIndex, store, view) {
304 | var v = value;
305 |
306 | if (value === null) {
307 | v = 'null';
308 | }
309 |
310 | if (record.data.text === 'undefined') {
311 | v = 'undefined';
312 | }
313 |
314 | return '' + v + '';
315 | }
316 | }
317 | ]
318 |
319 | ## オーバーライドの文書化
320 |
321 | デフォルトをオーバーライドする必要があるか、機能を継承した場合、その変更を完全に明白にするために、インライン コメントとブロック コメントを積極的に活用しましょう。
322 |
323 | // EXTJS-12345 のバグのオーバーライド
324 | Ext.define('MyApp.override.CustomNumberField', {
325 | override : 'Ext.form.field.Number',
326 |
327 | initComponent: function () {
328 | var me = this,
329 | allowed;
330 |
331 | me.callParent();
332 |
333 | me.setMinValue(me.minValue);
334 | me.setMaxValue(me.maxValue);
335 |
336 | // 設定されたオプションをベースにマスキング/ストリッピングする正規表現を構築
337 | if (me.disableKeyFilter !== true) {
338 | allowed = me.baseChars + '';
339 | if (me.allowDecimals) {
340 | //OVERRIDE THIS LINE...
341 | //allowed += me.decimalSeparator;
342 | allowed += ',.';
343 | }
344 | }
345 | }
346 | });
347 |
348 | この文書化は、アップグレード処理の際に便利です。 たとえば、バグ EXTJS-12345 は最新版でフィックスされたら、このオーバーライドは完全に取り除くことができます。
349 |
350 | ## インデントや空白
351 |
352 | 多くの開発者には、スペースをあける時のタブとスペースの話題に関する断固たる意見があるものです。 タブのサイズは予測できないので、Sencha は自身のコードでは 4つのスペースを利用することにしています。 読みやすいコードを保証することができる唯一の方法は、スペースの利用を実施することです。 最終的な目的は一貫性があることだけなので、どちらを選ぼうともそれらを交ぜてはいけません。
353 |
354 | // 悪い
355 | function doSomething (isTrue) {
356 | // < 1つのスペース
357 | if (isTrue) {
358 | // <<< 3 つのスペース
359 | }// もう混乱し始めてます
360 | }
361 |
362 | // 良い
363 | function doSomething (isTrue) {
364 | // <<<< 4 つのスペース
365 | if (isTrue) {
366 | // <<<< 4 ここでも 4つのスペース
367 | }
368 | }
369 |
370 | 一方、Senchaも、読みやすいコードを作るのに必要なホワイトスペースを使うことを推奨します。
371 |
372 | ### 一貫性の利点
373 |
374 | Senchaが推奨するひとつの技法は、関数宣言の括弧の前にはスペースを空け、実行する時にはスペースを空けないことです。
375 | そうすることで、テキスト検索で関数宣言とは分けて、関数を実行している箇所を簡単に探せるようになります。
376 |
377 | 下記はその例です:
378 |
379 | function foo () { // "foo" と "(" の間にスペースがあります
380 | return 42;
381 | }
382 |
383 | var x = foo(); // "foo" と "(" の間にスペースがありません
384 |
385 | このようにすることで、"foo(" と検索すると、'foo'関数を実行している箇所だけを見つけることができます。
386 |
387 | Senchaが推奨するその他の技法は、オブジェクトのプロパティ名と `:` の間でスペースを空けないことです。
388 | (これもまた、テキスト検索で利点があります)
389 |
390 | 下記はその例です:
391 |
392 | Ext.define('Ext.panel.Panel', {
393 | collapse: function () ...
394 | });
395 |
396 | "collapse:" を検索すると、呼び出し以外の`collapse`の実装を探すことができます。逆に、"collapse(" で呼び出しを探せます。
397 |
398 | ## 行の長さ
399 |
400 | 一行あたりの文字数制限については、誰もが同意するというわけではありませんが、 Sencha では一般的に行の幅を制限しようとしています。 この制限は任意で(例えば80または100文字)厳しく押しつけることはしませんが、目的は開発者が水平スクロールする量を減らすのが目的です。
401 |
402 | 誰でも線につき性格のために特定の制限に同意するというわけではない、しかし、Senchaは一般的に行の幅を制限しようとしています。 この制限は任意で(例えば80または100文字)、厳しく実施されることができない、しかし、ゴールは水平スクロールの量を開発者のために減らすことになっている。
403 |
404 | 明確な制限より長いひもは、ストリング連結を使っている複数の線の向こうに書かれなければならない。 決められた制限よりも長い文字列は、文字列連結を使って複数行にわたって記述します。
405 |
406 | ## メソッドやブロックの長さ
407 |
408 | コードブロックがどれくらいの長さになったら、機能をより小さなユーティリティ メソッドに分割することを考えますか?
409 |
410 | 良い経験則は、メソッドやコードブロックの長さを (例えば50または100行に) 制限することです。それによりそれほど大きくならずに済みます。 短いメソッドはテストしやすく、開発者がすぐに理解することができます。
411 |
412 | ## ファイルの長さ
413 |
414 | ファイルの行数がどれくらいになったら機能をミックスインやモジュールに分割することを考えますか?
415 |
416 | メソッド/ブロックの長さと同じように、コメントもファイルの長さに影響します。 仮想クラスは、インターフェースや基本ラインを定義するので、通常より長くなりやすくなります。 それでもやはり、任意のファイル長 (500または1000行) を定めると、クラスをリファクタリングする必要があるかどうかの兆候を把握できます。
417 |
--------------------------------------------------------------------------------
/Readable_JavaScript.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # Writing Readable JavaScript
6 |
7 | The importance of writing "readable" JavaScript simply cannot be overstated. Be kind to the others on your team,
8 | and your future self, by writing code that is easy to digest.
9 |
10 | In his book *Facts and Fallacies of Software Engineering*, Robert Glass discusses how simply
11 | "understanding the existing product" consumes roughly 30% of a developer's time. Glass frames this point within the
12 | context of the software maintenance cycle -- and while we will move our discussion to maintainability soon,
13 | Sencha recommends prioritizing the following points to make your codebase clear and coherent:
14 |
15 | - [Naming Conventions](#Naming_Conventions)
16 | - [Comments and Documentation](#Comments_Documentation)
17 | - [Documenting Overrides](#Documenting_Overrides)
18 | - [Spacing and White Space](#Spacing_White_Space)
19 | - [Line Length](#Line_Length)
20 | - [Block Length](#Block_Length)
21 | - [File Length](#File_Length)
22 |
23 | ## Naming Conventions
24 |
25 | > *"There are only two hard things in Computer Science: cache invalidation, naming things, and off-by-one errors."*
26 |
27 | Many people only name a few things in their life: a pet, a child, or something particularly personal and meaningful.
28 | In general, naming things is difficult because there is a perceived finality to the process
29 | (e.g. you rarely re-name a pet) -- but in software development, one typically has to name things far more often
30 | than the average person.
31 |
32 | Software developers might name thousands of new things per year: variables, classes, applications, etc. Each name
33 | attempts to capture the essence or purpose of the concept being named -- but because programs use more names than
34 | can be reasonably remembered, the names must be conceived consistently in order to help others understand, fix,
35 | and extend that same code months or years later. This idea is often referred to as "self-documenting code".
36 |
37 | Let's examine the areas in which naming conventions should be applied and how Sencha handles each case.
38 |
39 | ### Namespaces, Classes, and Constructors
40 |
41 | Sencha always uses *TitleCase* when creating top-level namespaces, classes, and constructors.
42 |
43 | // "MyClass" is a constructor :: new MyClass();
44 | MyClass = function () {};
45 |
46 | Intermediate namespaces should be short, descriptive and lowercase.
47 |
48 | // "Foo" as the top-level namespace
49 | // "bar" as an intermediate-level namespace
50 | // "Baz" as the class name
51 | Foo.bar.Baz = {};
52 | Ext.data.reader.Json = {};
53 |
54 | ### Functions
55 |
56 | Sencha always uses *camelCase* when creating functions. We also recommend the use a leading underscore "_" when
57 | naming private functions and methods that are not encapsulated by a closure.
58 |
59 | // function expression
60 | var sortSomeStuff = function () {};
61 |
62 | // function declaration
63 | function findSomething () {}
64 |
65 | // the same concept applies to object functions
66 | var someObject = {
67 | objectMethod: function () {},
68 |
69 | _privateMethod: function () {}
70 | };
71 |
72 | Note: more information about using function expressions vs. function declarations can be found in
73 | section [Functions](Preventing_JavaScript_Errors.md#Functions).
74 |
75 | ### Local Variables and Object Properties
76 |
77 | Always use `var` to declare local variables -- not doing so will result in the creation of global variables, and we want
78 | to avoid polluting the global namespace. See the [Constants and Global Variables](#Constants_Global_Vars) section below
79 | for more details.
80 |
81 | // bad
82 | foo = true;
83 |
84 | // good
85 | var foo = true;
86 |
87 | Sencha always uses *camelCase* when creating local variables and object properties. We also recommend the use a
88 | leading underscore "_" when naming private properties.
89 |
90 | // local variable
91 | var fooBar = true;
92 |
93 | // object property
94 | var someObject = {
95 | someProperty: true,
96 |
97 | _privateProperty: true
98 | };
99 |
100 | Variables should be given meaningful names, so that the intended purpose and functionality of the variables is
101 | clear (while also concise). Avoid single letter names; the lone exception to this rule would be an iterator.
102 |
103 | // bad, too short. Not descriptive and easy to confuse with number "1"
104 | var l = group.length;
105 |
106 | // bad, variable name is unnecessarily long
107 | var mainClassConfigVariableSectionOneRefreshInterval = 5000;
108 |
109 | // good, variable name is concise yet still meaningful
110 | var len = group.length;
111 |
112 | // iterators are an exception
113 | var i;
114 | for (i = 0; i < len; i++) {}
115 |
116 | Use one `var` declaration when creating multiple variables because it is easier to read. Sencha recommends
117 | declaring each variable assignment on a new line; declare unassigned variables last, though these can be on the
118 | same line.
119 |
120 | This helps to provide a visual cue to the person reading your code about the initial state of the variables
121 | within the current scope.
122 |
123 | // bad
124 | var foo = 1;
125 | var bar = 2;
126 | var baz;
127 | var fuz;
128 |
129 | // good
130 | var foo = 1,
131 | bar = 2,
132 | baz, fuz;
133 |
134 | ### Constants and Global Variables
135 |
136 | Sencha recommends using *CONSTANT_CASE* when creating global variables because of the clear visual
137 | indication that the variable is special.
138 |
139 | // bad
140 | userID = '12345';
141 |
142 | // good
143 | USER_ID = '12345';
144 |
145 | Having said that, Sencha prefers to avoid global variables and constants altogether. We feel that enterprise
146 | applications benefit from using properly-namespaced classes instead because it's always clear where a value
147 | has been defined.
148 |
149 | // better
150 | MyApp.authentication.User = {
151 | id: '12345'
152 | };
153 |
154 | ### Special Cases
155 |
156 | Other special cases also exist -- for example, naming references to `this`.
157 |
158 | As an internal convention, Sencha uses the name `me` when there is a need to capture a reference to `this` within
159 | a closure. Not everyone agrees -- Christian Johansen is [a notable example](https://gist.github.com/cjohansen/4135065) --
160 | but the greater point is to manage these special cases consistently throughout your codebase.
161 |
162 | Person.logger = function () {
163 | var me = this; // "me" will be used consistently
164 |
165 | return function () {
166 | console.log(me);
167 | };
168 | };
169 |
170 | Another important thing to note is that `this` is a keyword and can't be compressed. In the Sencha frameworks,
171 | we abide by the rule of four: if a given scope references `this` four or more times,
172 | cache `this` using the local variable `me` as it will make the minified source smaller.
173 |
174 | // bad
175 | function foo () {
176 | this.x = 1;
177 | this.y = 2;
178 | this.z = 3;
179 | this.u = 4;
180 | }
181 |
182 | // good
183 | function foo () {
184 | var me = this;
185 | me.x = 1;
186 | me.y = 2;
187 | me.z = 3;
188 | me.u = 4;
189 | }
190 |
191 | // comparison of minified output
192 | function f(){this.x=1;this.y=2;this.z=3}
193 | function f(){var e=this;e.x=1;e.y=2;e.z=3}
194 |
195 | function f(){this.x=1;this.y=2;this.z=3;this.u=4;}
196 | function f(){var e=this;e.x=1;e.y=2;e.z=3;e.u=4;} // 4 is now shorter!
197 |
198 | function f(){this.x=1;this.y=2;this.z=3;this.u=4;this.v=5;}
199 | function f(){var e=this;e.x=1;e.y=2;e.z=3;e.u=4;e.v=5;}
200 |
201 | ### Reserved Words
202 |
203 | Don't use reserved words as keys because they break things in older versions of Internet Explorer. Use readable synonyms
204 | in place of reserved words instead.
205 |
206 | // bad
207 | var model = {
208 | name: 'Foo',
209 | private: true // reserved word!
210 | };
211 |
212 | // good
213 | var model = {
214 | name: 'Foo',
215 | hidden: true
216 | };
217 |
218 |
219 | Note: "readable synonyms" must actually be words.
220 |
221 | // bad
222 | var car = {
223 | class: 'Ford' // reserved word!
224 | };
225 |
226 | // bad
227 | var car = {
228 | klass: 'Ford' // PLEASE don't ever do this!
229 | };
230 |
231 | // good
232 | var car = {
233 | brand: 'Ford'
234 | };
235 |
236 | ## Comments and Documentation
237 |
238 | Generally speaking, good code is supposed to be self-explanatory. However comments play two vital roles in promoting
239 | readable code: documentation, and intent (via inline comments).
240 |
241 | ### Documentation
242 |
243 | System-wide documentation is vital to developing large codebases. Using tools like
244 | [JSDuck](https://github.com/senchalabs/jsduck) it is easy to build an API
245 | reference for your codebase, making it significantly easier for your team (and others) to digest.
246 |
247 | [Sencha](http://docs.sencha.com/extjs/5.0/apidocs/) uses JSDuck internally, which follows the JavaDoc style for block
248 | comments. See the [JSDuck wiki](https://github.com/senchalabs/jsduck/wiki) for more information.
249 |
250 | /**
251 | * @class MyApp.foo.Bar
252 | */
253 | MyApp.foo.Bar = function () {
254 | var baz = true;
255 |
256 | return {
257 | /**
258 | * @method
259 | */
260 | utilityMethod: function () {
261 | return baz;
262 | }
263 | };
264 | };
265 |
266 | ### Inline Comments
267 |
268 | Many developers feel that code ought to be "self-documenting" and therefore inline comments are to be avoided.
269 | Sencha doesn't necessarily agree with the rigidness of that mindset; we believe that comments should always be
270 | added when the intent or purpose of any code isn't completely explicit, but the code itself ought to be clear
271 | enough to follow logically.
272 |
273 | // In a majority of cases, the controller ID will be the same as the name.
274 | // However, when a controller is manually given an ID, it will be keyed
275 | // in the collection that way. So if we don't find it, we attempt to loop
276 | // over the existing controllers and find it by classname
277 | if (!controller) {
278 | all = controllers.items;
279 | for (i = 0, len = all.length; i < len; ++i) {
280 | cls = all[i];
281 | className = cls.getModuleClassName();
282 | if (className && className === name) {
283 | controller = cls;
284 | break;
285 | }
286 | }
287 | }
288 |
289 | Regular expressions should also always be explained with a comment because of their inherently confusing syntax.
290 |
291 | // match Roman Number input
292 | var romanNums = /^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$/;
293 |
294 | Commenting out entire blocks of code should be generally avoided because they serve no purpose and create bloated code.
295 |
296 | // Why leave the following code in production?
297 | items : [
298 | //{
299 | // xtype : 'booleancolumn',
300 | // width : 5,
301 | // resizable : false,
302 | // defaultWidth : 5,
303 | // sortable : false,
304 | // dataIndex : 'isOwn',
305 | // groupable : false,
306 | // hideable : false,
307 | // lockable : false,
308 | // tdCls : 'indicator',
309 | // falseText : ' ',
310 | // trueText : ' '
311 | //},
312 | //{
313 | // xtype : 'gridcolumn',
314 | // dataIndex : 'key',
315 | // text : 'Binding Key',
316 | // flex : 1
317 | //},
318 | {
319 | xtype : 'templatecolumn',
320 | dataIndex : 'boundTo',
321 | text : 'Bound To',
322 | flex : 1,
323 | tpl : '\\{{boundTo}\\}'
324 | },
325 | {
326 | xtype : 'gridcolumn',
327 | dataIndex : 'value',
328 | text : 'Value',
329 | flex : 1,
330 | renderer : function (value, metaData, record, rowIndex, colIndex, store, view) {
331 | var v = value;
332 |
333 | if (value === null) {
334 | v = 'null';
335 | }
336 |
337 | if (record.data.text === 'undefined') {
338 | v = 'undefined';
339 | }
340 |
341 | return '' + v + '';
342 | }
343 | }
344 | ]
345 |
346 | ## Documenting Overrides
347 |
348 | In cases where you need to override default or inherited functionality, both inline and block comments are
349 | actively encouraged so that the changes are perfectly clear.
350 |
351 | // OVERRIDE for bug EXTJS-12345
352 | Ext.define('MyApp.override.CustomNumberField', {
353 | override : 'Ext.form.field.Number',
354 |
355 | initComponent: function () {
356 | var me = this,
357 | allowed;
358 |
359 | me.callParent();
360 |
361 | me.setMinValue(me.minValue);
362 | me.setMaxValue(me.maxValue);
363 |
364 | // Build regexes for masking and stripping based on the configured options
365 | if (me.disableKeyFilter !== true) {
366 | allowed = me.baseChars + '';
367 | if (me.allowDecimals) {
368 | //OVERRIDE THIS LINE...
369 | //allowed += me.decimalSeparator;
370 | allowed += ',.';
371 | }
372 | }
373 | }
374 | });
375 |
376 | This documentation will often come in handy during an upgrade process. For example, the bug EXTJS-12345 might have
377 | been fixed in the latest version -- so this override could be removed completely.
378 |
379 | ## Spacing and White Space
380 |
381 | Many developers have strong opinions on the topic of tabs-vs-spaces for spacing. Sencha advocates the use of
382 | four spaces in our own code because tab sizes are unpredictable; the only way we can guarantee readable code is
383 | to enforce the use of spaces. Ultimately the goal is just to have consistency, so whatever your choice don't mix them!
384 |
385 | // bad
386 | function doSomething (isTrue) {
387 | // < 1 space in
388 | if (isTrue) {
389 | // <<< 3 spaces in?
390 | }// now you're just being confusing...
391 | }
392 |
393 | // good
394 | function doSomething (isTrue) {
395 | // <<<< 4 spaces in!
396 | if (isTrue) {
397 | // <<<< 4 spaces in again!
398 | }
399 | }
400 |
401 | On the other hand, Sencha also advocates for using as much white space as necessary to make your code easier to read.
402 |
403 | ### Benefits of Consistency
404 |
405 | One technique Sencha recommends is to maintain spaces before the parentheses of function declarations but
406 | not for function calls. This allows text searches to more easily find calls to functions separately from their
407 | declartions.
408 |
409 | For example:
410 |
411 | function foo () { // Note the space between "foo" and "("
412 | return 42;
413 | }
414 |
415 | var x = foo(); // Note no space between "foo" and "("
416 |
417 | Now searches for "foo(" will find only the calls to `foo`.
418 |
419 | Another technique Sencha recommends is to place no space between the name of an object property and the `:`
420 | (again for benefits in text search).
421 |
422 | For example:
423 |
424 | Ext.define('Ext.panel.Panel', {
425 | collapse: function () ...
426 | });
427 |
428 | Searches for "collapse:" will find implementations of `collapse` and not invocations. Conversely for
429 | "collapse(".
430 |
431 | ## Line Length
432 |
433 | Not everyone agrees with the specific limit for characters-per-line, but Sencha generally tries to limit line length.
434 | This limit can be arbitrary (e.g. 80 or 100 characters) and not rigidly enforced, but the goal is to reduce the amount
435 | of horizontal scrolling for the developer.
436 |
437 | Strings longer than the decided limit should be written across multiple lines using string concatenation.
438 |
439 | ## Method and Block Length
440 |
441 | How long can a method or code block get before you consider breaking functionality into smaller utility methods?
442 |
443 | A good rule-of-thumb is to limit the length of method and code blocks (e.g. 50 or 100 lines) so that they are not
444 | trying to do too much. Shorter methods are easier to test, and smaller sections of code are more quickly
445 | comprehended by developers.
446 |
447 | ## File Length
448 |
449 | How long should a file be before you consider breaking functionality into mixins, modules or other utility classes?
450 |
451 | As with method/block length, comments can easily impact the length of a file. Abstract classes might also be longer
452 | than usual because they define interfaces and baseline functionality. Nevertheless, defining an arbitrary file
453 | length (e.g. 500 or 1000 lines) might give you an indication of whether-or-not a class might need to be refactored.
454 |
--------------------------------------------------------------------------------