ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptを深く理解するシリーズ(1) 高品質なJavaScriptコードを書くための基本ポイント_javascriptスキル

JavaScriptを深く理解するシリーズ(1) 高品質なJavaScriptコードを書くための基本ポイント_javascriptスキル

WBOY
WBOYオリジナル
2016-05-16 17:57:141026ブラウズ

具体的には、グローバル変数の回避、単一変数宣言の使用、ループ内の長さのプリキャッシュ、次のコード読み取りなど、高品質の JavaScript を記述するための要素がいくつかあります。
この概要には、API ドキュメントの作成、ピア レビューの実行、JSLint の実行など、コードにはあまり関係なく、コード作成全体に関連したいくつかの習慣も含まれています。これらの習慣とベスト プラクティスは、数か月または数年後に振り返ったときに誇りに思える、より適切で理解しやすく保守しやすいコードを作成するのに役立ちます。
保守可能なコードの作成
ソフトウェアのバグの修正には費用がかかり、特にこれらのバグが過去にリリースされたソフトウェアに潜んでいて徐々に現れる場合には、時間の経過とともに、これらのバグのコストも増加します。バグを見つけたら、コードが解決しようとしている問題がまだ頭の中に明確に残っているうちに、バグを修正するのが最善です。そうしないと、他のタスクに移り、コードの特定の部分を忘れてしまい、しばらくしてからそのコードを再検討する必要があります:
時間をかけて問題を学び、理解する
問題となっているコードの理解に時間がかかる
また、特に大規模なプロジェクトや企業の場合、バグを修正するのはコードを書いた人ではないという問題もあります(そして、バグを発見した人とバグを修正した人は、同一人物)。したがって、自分が少し前に書いたコードであっても、チームの他のメンバーが書いたコードであっても、コードを理解するのにかかる時間を短縮する必要があります。これは収益 (収益) と開発者の幸福に関係します。なぜなら、レガシー コードの保守に何時間も何日も費やすのではなく、新しくエキサイティングなものを構築する必要があるからです。
ソフトウェア開発に関するもう 1 つの事実は、コードを読み取るのに、コードを書くよりもはるかに長い時間がかかるということです。問題について集中して深く考えると、午後に座って大量のコードを書くことができることがあります。
コードは非常に迅速に動作しますが、アプリケーションが成熟するにつれて、他の多くのことが発生し、レビュー、変更、調整が必要になります。例:
バグが公開される
アプリケーションに新しい機能が追加される
プログラムが新しい環境で動作する (たとえば、新しいブラウザが市場に登場する)
コードの再利用
コードを最初から完全に書き直すか、別のアーキテクチャまたは別の言語に移植する必要があります
これらの変更により、少数の人が数時間かけて書いたコードが、最終的には読むのに数週間かかることになります。 。このため、メンテナンス可能なコードを作成することがアプリケーションの成功にとって重要です。
保守可能なコードの意味:
読みやすい
一貫性がある
予測可能
同じ人が書いたように見える
文書化されている
最小限のグローバル変数 (グローバルの最小化)
JavaScript は次の方法でスコープを管理します機能。関数内で宣言された変数は関数内でのみ使用でき、関数の外では使用できません。一方、グローバル変数は関数の外で宣言されるか、宣言されずに単に使用されます。
各 JavaScript 環境には、関数の外部でこれを使用するときにアクセスできるグローバル オブジェクトがあります。作成したすべての変数は、このグローバル オブジェクトのプロパティになります。ブラウザでは、便宜上、グローバル オブジェクトには window と呼ばれる追加のプロパティがあり、これは (通常は) グローバル オブジェクト自体を指します。次のコード スニペットは、ブラウザ環境でグローバル変数を作成してアクセスする方法を示しています。

コードをコピーします コードは次のとおりです。

myglobal = "hello"; // 推奨されません
console.log(myglobal) // "hello"
console.log(window.myglobal); "
console.log(window["myglobal"]); // "こんにちは"
console.log(this.myglobal); // "こんにちは"

グローバル変数の問題
グローバル変数の問題は、これらのグローバル変数が JavaScript アプリケーションと Web ページのすべてのコードで共有され、同じグローバル名前空間に存在することです。したがって、プログラムの 2 つの異なる部分で、名前は同じで関数が異なるグローバル変数を定義すると、名前の競合が避けられません。
Web ページには、ページの開発者が作成したものではないコードが含まれることもよくあります。たとえば、
サードパーティの JavaScript ライブラリ
広告主のスクリプト コード
サードパーティのユーザー追跡および分析スクリプト コード
さまざまな種類のウィジェット、ロゴ、ボタン
たとえば、サードパーティのスクリプトは result というグローバル変数を定義し、その後、関数内でも result というグローバル変数を定義します。その結果、後の変数が前の変数を上書きし、サードパーティのスクリプトが突然げっぷをすることになります。
したがって、他のスクリプトと良い隣人でありたい場合は、グローバル変数の使用をできるだけ少なくすることが重要です。名前空間モードや自動関数の即時実行など、グローバル変数を削減するためのいくつかの戦略については、本書の後半で説明しますが、グローバル変数を削減するために最も重要なことは、常に var を使用して変数を宣言することです。
JavaScript の 2 つの特性により、無意識のうちにグローバル変数を作成するのは驚くほど簡単です。まず、変数は宣言しなくても使用できます。第 2 に、JavaScript には暗黙的なグローバルの概念があり、宣言していない変数はグローバル オブジェクト プロパティになります。以下のコードを参照してください。
コードをコピー コードは次のとおりです。

function sum( x, y) {
// 非推奨: 暗黙的なグローバル変数
result = x y;
return result;

このコードの結果は宣言されていません。 。コードは引き続き正常に動作しますが、関数を呼び出した後、余分なグローバル名前空間が作成されることになり、これが問題の原因となる可能性があります。
改善された sum() 関数で示されているように、経験則では常に var を使用して変数を宣言します。

コードをコピー コードは次のとおりです。
function sum(x, y) {
var result = x y;
return result;


別の作成 暗黙的なグローバル変数の反例は、タスクチェーンを使用した部分的な var 宣言です。次のスニペットでは、a はローカル変数ですが、b はグローバル変数です。これは意図した結果ではない可能性があります:


// 反例、
function foo() {
var a = b = 0;
// ...
}


なぜこの現象が起こるかというと、この右から左への代入は、まず代入式 b = 0 であり、この場合 b が宣言されていないからです。この式の戻り値は 0 であり、この 0 は var で定義されたローカル変数 a に代入されます。言い換えれば、次のように入力したようなものです:
var a = (b = 0);
変数を宣言する準備ができている場合は、グローバル変数などの予期せぬ結果を招くことなくチェーン割り当てを使用することをお勧めします。


function foo() {
var a, b;
// ... a = b = 0; // 両方のローカル変数
}


ただし、グローバル変数を避けるもう 1 つの理由は移植性です。コードを別の環境 (ホスト) で実行したい場合、グローバル変数を使用するのは薄氷です。元の環境に存在しないホスト オブジェクトを誤って上書きしてしまうためです (そのため、名前は安全に使用できると考えましたが、実際には上記が当てはまらない場合もあります)。
var を忘れた場合の副作用
暗黙的なグローバル変数と明示的に定義されたグローバル変数の間には小さな違いがあり、それは、delete 演算子を使用して変数を未定義のままにする機能です。
var を通じて作成されたグローバル変数 (関数の外のプログラムで作成されたもの) は削除できません。
var を使用せずに作成された暗黙的なグローバル変数は (関数内で作成されたかどうかに関係なく) 削除できます。
これは、技術的には、暗黙的なグローバル変数は実際にはグローバル変数ではなく、グローバル オブジェクトのプロパティであることを示しています。属性は削除演算子で削除できますが、変数は削除できません:


コードをコピー コードは次のとおりです:

// 3 つのグローバル変数を定義します
var global_var = 1;
global_novar = 2; // ネガティブ教材
(function () {
global_fromfunc = 3; // ネガティブ教材教科書
}());
// 削除してみます
delete global_var; // true
delete global_fromfunc; // テストこれを削除します
typeof global_var; // "number"
typeof global_novar; // "unknown"
typeof global_fromfunc; // "unknown"
コードをコピーします
ES5 厳密モードでは、宣言されていません変数を操作すると、エラーがスローされます (前のコード スニペットの 2 つの否定的な例のように)。
グローバル オブジェクトへのアクセス
ブラウザでは、window 属性を介してコード内のどこからでもグローバル オブジェクトにアクセスできます (名前が window のローカル変数であると宣言するなど、とんでもないことをしない限り)。ただし、他の状況では、この便利なプロパティは別の名前で呼ばれる可能性があります (またはプログラムで使用できない場合もあります)。ハードコーディングされたウィンドウ識別子を使用せずにグローバル オブジェクトにアクセスする必要がある場合は、任意のレベルの関数スコープで次の操作を行うことができます:
var global = (function () {
return this;
} ());


このメソッドは (新規構築ではなく) 関数内の関数として呼び出され、常にグローバル オブジェクトを指すため、いつでもグローバル オブジェクトを取得できます。実際、このバグは ECMAScript 5 の厳密モードには当てはまらないため、厳密モードでは別の形式を取る必要があります。たとえば、JavaScript ライブラリを開発している場合は、コードを即時関数でラップし、グローバル スコープからこれへの参照を即時関数のパラメーターとして渡すことができます。
単一の var パターン
関数の先頭で単一の var ステートメントを使用すると、次のような利点があります。
関数に必要なすべてのローカル部分を見つけるための単一の場所が提供されます。 🎜> 定義前に変数が使用される場合の論理エラーを防ぐ
宣言されたグローバル変数を覚えておくのに役立つため、グローバル変数の数が少なくなります //zxx: ここで少し混乱しています...
コードが少なくなります (型、値、
単一の var フォームは次のようになります:



コードをコピー コードは次のようになります: function func() {
var a = 1,
b = 2,
sum = a b,
myobject = {},
i ,
j;
// 関数本体...
}


1 つの var ステートメントを使用して、カンマで区切って複数の変数を宣言できます。このように変数と値を同時に初期化すると良いでしょう。これにより、論理エラー (初期化されていないが宣言されたすべての変数の初期値が未定義) が防止され、コードの可読性が向上します。コードを確認すると、初期化された値に基づいて、これらの変数の一般的な目的 (オブジェクトとして使用されるか整数として使用されるかなど) を知ることができます。
前のコードの sum = a b など、宣言時に実際の作業を行うこともできます。別の例として、DOM (Document Object Model) 参照を使用する場合、単一の var DOM 参照をローカルとして指定できます。



コードをコピー コードは次のとおりです: function updateElement() {
var el = document.getElementById("result"),
style = el.style
// el と style を使用して他の処理を行います...
}


ホイスティング: 分散変数に関する問題 (ホイスティング: 分散変数に関する問題)
JavaScript では、関数内のどこでも複数の var ステートメントを宣言でき、それらは宣言されたかのように動作します。関数の先頭にはホイスティングと呼ばれる動作があります。変数を使用し、その後関数内でそれを再宣言すると、ロジック エラーが発生する可能性があります。 JavaScript の場合、変数が同じスコープ (同じ関数) 内にある限り、var 宣言の前に使用された場合でも、その変数は宣言されているとみなされます。次の例を見てください:



コードをコピー コードは次のとおりです: // 反例
myname = "global"; // グローバル変数
function func() {
alert(myname) // "未定義"
var myname = "local"; ); // "ローカル"
}
func();
この例では、最初のアラートが「global」でポップアップし、2 番目のアラートが「loacl」でポップアップすると考えるかもしれません。最初のアラートの時点では myname が宣言されていなかったため、この期待は理解できます。この時点では、関数は当然グローバル変数 myname を参照する必要がありますが、これは実際の動作ではありません。最初のアラートは「未定義」としてポップアップ表示されます。これは、myname が (後で宣言されても) 関数のローカル変数として扱われ、すべての変数宣言が関数の先頭まで保留されるためです。したがって、この混乱を避けるために、使用するすべての変数を事前に宣言することが最善です。
上記のコード スニペットは次のように動作します:
コードをコピーします コードは次のとおりです:

myname = "global"; // グローバル変数
function func() {
var myname; // var myname = unknown; // と同等"unknown"
myname = "local";
alert(myname); // "local"}
func(); 完全を期すために、もう一度触れておきます。実行レベルではもう少し複雑です。コード処理は 2 つの段階に分かれています。最初の段階は、変数、関数の宣言、および通常の形式でのパラメーターの作成です。これは、コンテキストを解析して入力する段階です。 2 番目のフェーズはコードの実行で、関数式と非修飾識別子 (宣言された変数用) が作成されます。ただし、実際的な目的のために、ECMAScript 標準では定義されておらず、動作を記述するために一般に使用される「ホイスティング」の概念を採用します。
for ループ (for ループ)
for ループでは、配列または配列に似たオブジェクト (引数や HTMLCollection オブジェクトなど) の値をループできます。通常のループ形式は次のとおりです:




コードをコピー
コードは次のとおりです: / /2 番目に最適なループ for (var i = 0; i < myarray.length; i ) {
// myarray[i] を使用して何かを実行します
}


この形式 ループの欠点は、ループするたびに配列の長さを取得する必要があることです。これにより、特に myarray が配列ではなく HTMLCollection オブジェクトである場合に、コードが削減されます。
HTMLCollections は、DOM メソッドによって返されるオブジェクトを指します。例:



コードをコピー
コードは次のとおりです: document.getElementsByName() document.getElementsByClassName()
document.getElementsByTagName()


DOM 標準より前に導入された他の HTMLCollection があります。まだ使用されています。



コードをコピー
コードは次のとおりです: document.images: すべての画像ページ上の要素 document.links: すべてのタグ要素
document.forms: すべてのフォーム
document.forms[0].elements: ページの最初のフォームのすべてのフィールド


コレクションの問題は、基礎となるドキュメント (HTML ページ) をリアルタイムでクエリすることです。これは、コレクションの長さにアクセスするたびに、リアルタイムで DOM にクエリを実行する必要があり、DOM 操作は一般にコストがかかることを意味します。
次のコードに示すように、値をループするときに配列 (またはコレクション) の長さをキャッシュするのが良い形式であるのはこのためです。



Copy code
コードは次のとおりです: for (var i = 0, max = myarray.length; i < max; i ) { / / Use myarray[ i] Do something
}


この方法では、このループ中に長さの値を 1 回だけ取得します。
コンテンツを取得するためのループ時の HTMLCollection の長さのキャッシュは、すべてのブラウザーで 2 倍 (Safari3) から 190 倍 (IE7) まで高速になります。 //zxx: このデータは非常に古いようです。参考までに
ループ内のコレクションを明示的に変更する場合 (たとえば、DOM 要素を追加する場合)、定数の代わりに長さの更新を選択することをお勧めします。
単一の var 形式を使用すると、次のようにループから変数を取り出すことができます。




コードをコピー
コード function looper() { var i = 0,
max,
myarray = [];
// ...
for (i = 0, max = myarray.length; i < max; i ) {
// myarray[i] で何かを実行します
}
}


この形式には、単一の var 形式に固執するため、一貫性という利点があります。欠点は、コードをリファクタリングするときに、ループ全体をコピーして貼り付けるのが少し難しいことです。たとえば、ある関数から別の関数にループをコピーする場合、新しい関数に i と max を導入できることを確認する必要があります (ここで役に立たない場合は、元の関数からそれらを削除する必要がある可能性があります) ) 失う)。
ループの最後の調整は、i を以下の式のいずれかに置き換えることです。
コードをコピー コードは次のとおりです:

i = i 1
i = 1

JSLint がこれを実行するように要求するのは、 - 「過度の扱いやすさ」を促進するためです。 //zxx: これは、コードをさらに難しくすることが目的だと思います。
これを直接無視すると、JSLint の plusplus オプションが false になります (デフォルトはデフォルトです)。
さらに 2 つのバリエーションがあり、わずかに改良されています。理由は次のとおりです。
変数が 1 つ減ります (最大値なし)
0 との比較に時間がかかるため、通常は 0 までのカウントダウンが高速になります。 配列と比較するよりも効率的です。長さまたは 0 ではないその他のもの
コードをコピー コードは次のとおりです:

/ /最初のバリエーション:
var i, myarray = [];
for (i = myarray.length; i–-;) {
// myarray[i ]を使用して何かを行います
}
//2 番目の方法は while ループを使用することです:
var myarray = [],
i = myarray.length;
while (i–-) {
// myarray[ を使用します。 i] to do something
}

これらの小さな改善はパフォーマンスにのみ反映され、JSLint は i-- の使用について文句を言います。
for-in ループ (for-in ループ)
for-in ループは、配列以外のオブジェクトを走査するために使用する必要があります。for-in を使用してループすることは、「列挙」とも呼ばれます。
技術的には、配列に対して for-in ループを使用できます (配列は JavaScript のオブジェクトであるため) が、これはお勧めできません。配列オブジェクトがカスタム関数で拡張されている場合、ロジック エラーが発生する可能性があるためです。また、for-inでは属性リストの順序(順序)は保証されません。したがって、配列には通常の for ループを使用し、オブジェクトには for-in ループを使用するのが最善です。
非常に重要な hasOwnProperty() メソッドがあり、オブジェクトのプロパティを走査するときにプロトタイプ チェーンからプロパティをフィルターで除外できます。
次のコード部分を考えてみましょう:
コードをコピーします コードは次のとおりです:

// Object
var man = {
hands: 2,
legs: 2,
heads: 1
}// コード内のどこか
//メソッドを追加する すべてのオブジェクトを指定します
if (typeof Object.prototype.clone === "unknown") {
Object.prototype.clone = function ()
}

;
この例では、オブジェクト リテラルを使用して定義された man という名前のオブジェクトがあります。 man 定義が完了した後のどこかで、 clone() と呼ばれる便利なメソッドがオブジェクト プロトタイプに追加されました。このプロトタイプ チェーンはライブです。つまり、すべてのオブジェクトが自動的に新しいメソッドにアクセスできるようになります。 man を列挙するときに clone() メソッドを回避するには、hasOwnProperty() メソッドを適用してプロトタイプのプロパティをフィルターする必要があります。フィルタリングが行われていない場合、 clone() 関数が表示されますが、これはほとんどの場合望ましくありません。

コードをコピー コードは次のとおりです:
// 1.
// for-in Loop
for (var i in man) {
if (man.hasOwnProperty(i)) { // Filter
console.log(i, ":", man[i]);
}
}
/* コンソール表示結果
手:​​ 2
脚: 2
頭: 1
*/
// 2.
/ / 裏側 例:
// hasOwnProperty() をチェックしない for-in ループ
for (var i in man) {
console.log(i, ":", man[i]); 🎜>}
/*
コンソールに結果が表示されます
hands: 2
legs: 2
heads: 1
clone: function()
*/


hasOwnProperty() を使用する別の方法は、Object.prototype のメソッドをキャンセルすることです。例:


for (var i in man ) {
if (Object.prototype.hasOwnProperty.call(man, i)) { // Filter
console.log(i, ":", man[i]);
}


利点は、man オブジェクトが hasOwnProperty を再定義するときに名前の競合を回避できることです。また、長いプロパティ ルックアップ オブジェクトのすべてのメソッドを回避し、ローカル変数を使用してオブジェクトを「キャッシュ」できます。
コードをコピーします コードは次のとおりです:

var i, hasOwn = Object.prototype。 hasOwnProperty;
for (i in man) {
if (hasOwn.call(man, i)) { // フィルター
console.log(i, ":", man[i]); 🎜>}
}

厳密に言えば、hasOwnProperty() を使用しないことは間違いではありません。タスクとコードにどの程度自信があるかによっては、ループを少しスピードアップするためにタスクをスキップできる場合があります。ただし、現在のオブジェクトの内容 (およびそのプロトタイプ チェーン) が不明な場合は、 hasOwnProperty() を追加する方が安全です。
書式変更 (JSLint によって渡されない) では、単純に中括弧が無視され、if ステートメントが同じ行に配置されます。利点は、ループ ステートメントが完全なアイデアのように読めることです (各要素には独自の属性 "X" があり、何かを行うには "X" を使用します):

Copy code コードは次のとおりです。
// 警告: JSLint 検出に失敗しました
var i, hasOwn = Object.prototype.hasOwnProperty
; (i in man) if (hasOwn.call(man, i)) { // フィルター
console.log(i, ":", man[i]);


(非) 組み込みプロトタイプの拡張)
コンストラクターのプロトタイプ属性の拡張は、機能を追加する非常に強力な方法ですが、場合によっては強力すぎる場合があります。
組み込みのコンストラクター プロトタイプ (Object()、Array()、または Function() など) を追加する誘惑にかられますが、コードが予測不能になるため、保守性が大幅に低下します。あなたのコードを使用する他の開発者は、おそらく、あなたが追加したメソッドではなく、組み込みの JavaScript メソッドを使用して継続的に動作することを好むでしょう。
また、プロトタイプに追加されたプロパティは、hasOwnProperty 属性が使用されていないときにループ内に表示される可能性があり、混乱を引き起こす可能性があります。
したがって、組み込みプロトタイプを追加しないことが最善です。次の条件が満たされる場合にのみ例外を作成するルールを指定できます:
ECMAScript または JavaScript 実装の将来のバージョンでは、常にこの機能が組み込みメソッドとして実装されることが予想されます。たとえば、ブラウザが追いつくまで、ECMAScript 5 で説明されているメソッドを追加できます。この場合、便利なメソッドを事前に定義するだけです。
カスタム プロパティまたはメソッドが存在しないことを確認した場合、コード内の別の場所にすでに実装されているか、サポートされているブラウザの JavaScript エンジンの一部である可能性があります。
あなたは変更を明確に文書化し、チームに伝えました。
これら 3 つの条件が満たされている場合は、次の形式でプロトタイプにカスタマイズした追加を行うことができます:


if (typeof Object.protoype.myMethod !== "function") {
Object.protoype.myMethod = function () {
// 実装。 ..
};
}


switch パターン
次のような switch ステートメントを使用すると、可読性と堅牢性を高めることができます。

コードをコピー
コードは次のとおりです。 var Inspection_me = 0, result = ''; Inspection_me) { ケース 0:
結果 = "ゼロ";
ケース 1:
結果 = "1";
デフォルト:
>result = "unknown";
}


この簡単な例で従うスタイル規則は次のとおりです:
各ケースとスイッチを揃えます (中括弧のインデント規則を除く)
各ケースのコード インデント
各ケースはブレーク クリアで終了
貫通を避けます (ブレークは意図的に無視されます)。スルーラインが最良のアプローチであると強く確信している場合は、読者によっては間違っていると思われる可能性があるため、必ずこれを文書化してください。
デフォルトでスイッチを終了: 大文字と小文字が一致しない場合でも、常に正常な結果が得られるようにします。
暗黙的な型キャストの回避
JavaScript 変数は、比較時に暗黙的に型変換されます。そのため、false == 0 または "" == 0 は true を返します。混乱を招く暗黙的な型変換を避けるために、値と式の型を比較す​​るときは、常に === 演算子と !== 演算子を使用してください。




コードをコピー


コードは次のとおりです:

var zero = 0;
if (zero === false) {
// ゼロは 0 で false ではないため実行されません
}
// 負の例
if (zero == false) {
// Executed...
}

== で十分だという考えもあります === は冗長です。たとえば、typeof を使用すると文字列が返されることがわかっているため、厳密な等価性を使用する理由はありません。ただし、JSLint は厳密な等価性を必要とするため、コードの見た目の一貫性が高まり、コード読み取り時のエネルギー消費が削減されます。 (「== は意図的なものですか、それとも見落としですか?」)
eval() を避ける
現在のコードで eval() を使用する場合は、「eval() は悪魔である」というマントラを思い出してください。このメソッドは任意の文字列を受け入れ、JavaScript コードとして処理します。問題のコードが事前にわかっている (実行時に決定されない) 場合、eval() を使用する理由はありません。コードが実行時に動的に生成される場合、eval を使用せずに同じ目標を達成するより良い方法があります。たとえば、角かっこ表記を使用して動的プロパティにアクセスする方が簡単で適切です。
コードをコピーします コードは次のとおりです。 :

// 否定的な例
var property = "name";
alert(eval("obj." property));
// より良い
var property = "name ";
alert(obj[property]);

eval() を使用すると、(ネットワークなどから) 実行されているコードが使用されている可能性があるため、セキュリティ上のリスクも生じます。改ざんされました。これは、Ajax リクエストからの JSON レスポンスを処理する場合によくある否定的な教訓です。このような場合、安全性と効率性を確保するには、JavaScript の組み込みメソッドを使用して JSON 応答を解析するのが最善です。ブラウザが JSON.parse() をサポートしていない場合は、JSON.org のライブラリを使用できます。
文字列を setInterval()、setTimeout()、および Function() コンストラクターに渡すことは、ほとんどの場合、eval() を使用することに似ているため、避ける必要があることを覚えておくことも重要です。舞台裏では、JavaScript はプログラムに渡す文字列を評価して実行する必要があります:
コードをコピー コードは次のとおりです:

// 負の例
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)",
//より良い
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000); new Function() コンストラクトは eval() に似ているため、注意して扱う必要があります。これは強力な構成要素になる可能性がありますが、誤用されることがよくあります。どうしても eval() を使用する必要がある場合は、代わりに new Function() を使用することを検討してください。 new Function() のコード評価はローカル関数スコープで動作するため、コード内で評価される var で定義された変数は自動的にグローバル変数にならないため、潜在的な利点はわずかです。自動グローバル変数を防ぐもう 1 つの方法は、eval() 呼び出しを即時関数にラップすることです。
次の例を考えてみましょう。ここでは、un のみが名前空間をグローバル変数として汚染します。



コードをコピーします コードは次のとおりです。 console.log(typeof un) / / "未定義"
console.log(typeof deux); // "未定義"
console.log(typeof trois); // "未定義"
var jsstring = "var un = 1; log(un );";
eval(jsstring); // ログ "1"
jsstring = "var deux = 2; console.log(deux);";
new Function(jsstring)( ); / / ログ "2"
jsstring = "var trois = 3; console.log(trois);";
(function () {
eval(jsstring);
}() ); // ログ "3"
console.log(typeof un); // 数値
console.log(typeof deux); / "unknown "


eval() と Function コンストラクトのもう 1 つの違いは、eval() がスコープ チェーンに干渉する可能性があるのに対し、Function() の方が安全であることです。 Function() をどこで実行しても、グローバル スコープのみが参照されます。したがって、局所的な変動汚染を非常によく回避できます。次の例では、 eval() は外側のスコープ内の変数にアクセスして変更できますが、Function では実行できません (using Function と new Function は同じであることに注意してください)。



コードをコピー
コードは次のとおりです。 (function () { var local = 1 ;
eval("local = 3; console.log(local)"); // ログ「3」
console.log(local); // ログ「3」
}( ));
(function () {
var local = 1;
Function("console.log(typeof local);")(); // 未定義のログを記録します
}());


parseInt() による数値変換
parseInt() を使用すると、文字列から数値を取得できます。このメソッドは省略されることが多いですが、省略すべきではありません。たとえば、文字列が「0」で始まる場合に問題が発生することがあります。たとえば、ECMAScript 3 では、フォーム フィールド部分を入力するときに、「0」で始まる文字列が 8 進数として扱われますが、これは ECMAScript で変更されました。 5.矛盾や予期しない結果を避けるために、常に基数引数を指定してください。
コードをコピーします コードは次のとおりです:

var month = "06",
year = "09";
month = parseInt(month, 10);

この例では、base パラメータを無視した場合parseInt (year) などの場合、戻り値は 0 になります。これは、「09」が 8 進数として扱われ (parseInt(year, 8) の実行など)、09 は 8 進数の有効な数値ではないためです。
置換方法は、文字列を次のような数値に変換することです。

コードをコピーします コードは次のとおりです。
"08" // 結果は 8
Number("08") // 8

これらは通常、parseInt() より高速です。 () メソッドは、名前が示すとおり、単純な解析と変換ではありません。ただし、たとえば「08 hello」と入力したい場合、parseInt() は数値を返しますが、それ以外の場合は NaN が返されます。

コーディング規約
コーディング規約を確立して従うことが重要です。これにより、コードに一貫性があり、予測可能になり、読みやすく理解しやすくなります。チームに新しく加わった開発者は、仕様を読み、他のチームメンバーが書いたコードを理解し、より早く作業を開始できます。
会議やメーリング リストでは、コーディング標準の特定の側面 (コードのインデント、タブ、スペースなど) をめぐって多くの白熱した議論が行われます。あなたが組織内での規範の採用を提案している場合は、さまざまな反対意見や強硬な意見に直面することを覚悟してください。コードを確立してしっかりと従うことは、コードの詳細にこだわるよりもはるかに重要であることを覚えておいてください。
インデント
コードは基本的にインデントなしでは読めません。唯一の問題は、インデントが一貫していないことです。仕様に従っているように見えますが、途中で混乱や驚きが生じる可能性があるからです。インデントを適切に使用することが重要です。
開発者の中には、タブのインデントを好む人もいます。これは、誰でもエディタを調整して、好みのスペース数でタブを表示できるためです。スペースを好む人もいますが、通常は 4 つですが、チームの全員が同じ基準に従っている限り、これは問題ではありません。たとえば、この本ではインデントに 4 つのスペースを使用しています。これは JSLint のデフォルトのインデントでもあります。
何をインデントする必要がありますか?ルールは単純で、中括弧の中に何を入れるかです。これは、関数本体、ループ (do、while、for、for-in)、if、switch、およびオブジェクト リテラルのオブジェクト プロパティを意味します。次のコードはインデントの使用例です。

コードをコピーします コードは次のとおりです:
関数アウター (a, b) {
var c = 1,
d = 2,
インナー;
if (a > b) {
インナー = function () {
return {
r: c - d
};
} else {
inner = function () {
return {
r: c d
};
};
}
return inner;


中括弧 {} (中括弧)
中括弧とも呼ばれます、以下同じ)は、オプションの場合でも常に使用する必要があります。技術的には、in または for にステートメントが 1 つしかない場合は中括弧は必要ありませんが、コードの一貫性が高まり、更新が容易になります。
ステートメントが 1 つだけある for ループがあると想像してください。解析エラーを起こさずに中括弧を無視できます。



コードをコピー コードは次のとおりです: // 悪い例
( var i = 0; i alert(i);


しかし、後で別のコード行が追加された場合はどうなるでしょうか?


コードをコピー コードは次のとおりです: // 悪い例
( var i = 0; i alert(i)
alert(i " は " (i % 2 ? "偶数"); 🎜>
2 番目のアラートはすでにループの外にあります。インデントに騙された可能性があります。長期的な計画の場合は、常に中括弧を使用することをお勧めします。これはコード 1 行に相当します。
コードをコピー コードは次のとおりです:

// 良い例
for (var i = 0; i alert(i); >}

条件が似ている場合:

コードをコピー コードは次のとおりです:
// Bad
if (true)
alert(1);
else
alert(2); {
alert(1);
} else {
alert(2);
}


開始括弧の場所)
開発者は場所について異なる設定を持っています左中括弧の - 同じ行または次の行。



コードをコピー コードは次のとおりです。 if (true) {
alert ("それは真実です!");
}
//または
if (true)
{
alert("それは真実です!");


この例では、仁は仁を、智は智を見たが、括弧の位置が違うと行動が異なる場合もある。これはセミコロン挿入メカニズムによるものです。JavaScript は好みを選ばないので、コード行をセミコロンで終了しないことを選択した場合でも、それを補ってくれます。この動作は、たとえばオブジェクト リテラルを返し、左括弧が次の行にある場合に問題を引き起こす可能性があります:



Copy code
コードは次のとおりです: // 警告: 予期しない戻り値 function func() {
return
// 次のコードは実行されません
{
name : "Batman"
}
}


関数が name 属性を持つオブジェクトを返すことを期待している場合は、驚かれるでしょう。暗黙のセミコロンがあるため、関数は未定義を返します。前のコードは次と同等です:



コードをコピーします
コードは次のとおりです: / / 警告: 予期しない function func() の戻り値 {
return unknown;
// 次のコードは実行されません
{
name : "Batman"
}
}


つまり、常に中括弧を使用し、その前にステートメントを常に同じ行に置きます:



コードをコピー
コードは次のとおりです。 function func() { return {
name : "Batman"
};


セミコロンに関する注意: 中括弧を使用するのと同じように、セミコロンは JavaScript パーサーによって暗黙的に作成される場合でも、常に使用する必要があります。これは、より科学的で厳密なコードを促進するだけでなく、前の例で示したように、混乱している領域を解決するのにも役立ちます。
ホワイトスペース (ホワイトスペース)
ホワイトスペースの使用は、コードの読みやすさと一貫性の向上にも役立ちます。英語の文章を書くとき、カンマやピリオドの後にスペースを使います。 JavaScript では、リストのような式 (カンマに相当) と終了ステートメント (「アイデア」の完成に関連する) の後にスペースを追加することで、同じロジックに従うことができます。
スペースを使用するのに適した場所は次のとおりです。
for ループのセミコロンで区切られた部分: for (var i = 0; i for などループ 複数の変数 (i および max) が次のように初期化されます: for (var i = 0, max = 10; i 配列項目を区切るカンマの後: var a = [1, 2, 3];
オブジェクト属性のカンマと、属性名と属性値を区切るコロンの後: var o = {a: 1, b: 2}; : myFunc(a , b, c)
関数宣言の中括弧の前: function myFunc() {}
匿名関数式 function の後: var myFunc = function () {};すべての演算子とオペランドを区切るためにスペースを使用することも効果的です。つまり、-、*、=、<、>、<=、>=、===、!==、&&、||、スペースは= などの前後に必須




コードをコピー


コードは次のとおりです:if (a && b && c) {
d = a % c;
a = d;
}
// 否定的な例
// スペースが欠けている、または不均等である
// コードがわかりにくくなります
var d = 0,
a = b 1;
if (a&&b&c) {
d=a % c;


注意する必要がある最後のスペースは、中括弧間のスペースです。スペースを使用するのが最善です。
関数、if-else ステートメント、ループ、オブジェクト リテラルの左中括弧 ({) の前
else または while の間の右中括弧 (})
スペースはファイルサイズが大きくなるという欠点がありますが、圧縮であればこの問題はありません。
コードの読みやすさに関して見落とされがちな側面は、垂直方向の空白の使用です。文献で段落を区切るのと同じように、空白行を使用してコード単位を区切ることができます。
命名規則
コードをより予測しやすく保守しやすくするもう 1 つの方法は、命名規則を採用することです。これは、変数と関数に同じ方法で名前を付ける必要があることを意味します。
以下は、推奨される命名規則の一部です。そのまま採用することも、好みに応じて調整することもできます。同様に、規範に従うことは、規範が何であるかよりも重要です。
コンストラクターを大文字で記述します (コンストラクターを大文字にする)
JavaScript にはクラスがありませんが、new によって呼び出されるコンストラクターがあります。 function の場合、関数名を見るだけで、これがコンストラクターであるべきか、通常の関数であるべきかがわかります。
コンストラクターに名前を付ける場合、大文字の最初の文字は暗示的な効果を持ちます。小文字で名前が付けられた関数とメソッドは、


コードをコピーしてください。 🎜> コードは次のとおりです。 function MyConstructor() {...}
function myFunction() {...}


単語の区切り )
変数名や関数名に複数の単語が含まれる場合、単語の分割については統一された標準に従うのが最善です。 「キャメルケース (キャメル) 命名法」と呼ばれる一般的な慣例があります。各単語の最初の文字を小文字にします。
コンストラクターの場合、MyConstructor() など、大文字のキャメルケースを使用できます。関数名とメソッド名には、myFunction()、calculateArea()、getFirstName() など、小文字のキャメルケースを使用できます。
変数が関数ではない場合はどうなりますか?開発者はキャメルケース表記をよく使用しますが、代わりに、first_name、favorite_bands、old_company_name のように、小文字の単語の後にアンダースコアを付けることもできます。この表記は、関数を他の識別子 (プロトタイプやオブジェクト) から視覚的に区別するのに役立ちます。
ECMAScript のプロパティとメソッドはすべて Camel 表記法を使用しますが、複数の単語を含むプロパティ名はまれです (正規表現オブジェクトの lastIndex プロパティとignoreCase プロパティ)。
その他の命名パターン
開発者は、言語機能を補ったり置き換えたりするために命名規則を使用することがあります。
たとえば、JavaScript では定数を定義する方法がないため (Number や MAX_VALUE などの組み込みの定数はいくつかありますが)、開発者はすべて大文字の規則を使用して、変数のライフ サイクル中に変更されない変数に名前を付けます。次のようなプログラム:
// 遠くからのみ見える貴重な定数
var PI = 3.14,
MAX_WIDTH = 800
コードをコピー
すべて大文字にする別の規則があります。 : グローバル変数名はすべて大文字です。グローバル変数にすべて大文字で名前を付けると、グローバル変数の数を減らすと同時に、区別しやすくなります。
仕様を使用して機能をシミュレートするもう 1 つの方法は、プライベート メンバーを使用することです。 JavaScript で真のプライベート性を実現することは可能ですが、開発者はプライベート プロパティまたはメソッドを示すためにアンダースコア接頭辞を使用する方が簡単であると考えています。次の例を考えてみましょう。



コードをコピーします コードは次のとおりです。 var person = {
getName: function () {
return this._getFirst() ' ' this._getLast();
},
_getFirst: function () {
// ...
},
_getLast: function () {
// ...
}
};
この例では、getName() はパブリック メソッドと部分的に安定した API を表します。また、_getFirst() と _getLast() はプライベートを示します。これらは依然として通常のパブリック メソッドですが、アンダースコア接頭辞は、これらのメソッドが次のバージョンで動作することが保証されておらず、直接使用できないことを person オブジェクトのユーザーに警告するために使用されます。 noman オプションを :false に設定しない限り、JSLint はアンダースコア接頭辞を使用しないことに注意してください。
一般的な _private 仕様の一部を次に示します。
name_ や getElements_() など、プライベートを示すには末尾のアンダースコアを使用します。
_protected 属性を示すにはアンダースコア接頭辞を使用し、__private (Private) を示すには 2 つのアンダースコア接頭辞を使用します。 ) 属性
Firefox の一部の組み込み変数属性は、言語の技術的な部分に属しておらず、__proto__ と __parent__ のように、先頭の 2 つのアンダースコアと末尾の 2 つのアンダースコアで表されます。
コメントを書く
他の誰もあなたと同じようにコードに触れないとしても、コードにコメントを付ける必要があります。通常、問題を深く研究すると、コードが何に使用されているかが明確にわかりますが、1 週間後にその問題に戻ってみると、それがどのように機能するかを理解するために多くの脳細胞を費やしたはずです。
明らかに、コメントは、変数ごとに、または行ごとに、という極端な使い方はできません。ただし、通常はすべての関数、そのパラメータと戻り値、または珍しいテクニックやメソッドを文書化する必要があります。コメントは、今後コードを読む人に多くの手がかりを与える可能性があることに注意してください。読者は、コードを理解するために (あまり読みすぎなくても) コメントと関数の属性名だけを必要とします。たとえば、特定のタスクを実行するプログラムが 5 行または 6 行ある場合、その行の目的とその行が存在する理由を説明すれば、読者はこの詳細をスキップできます。コードに対するコメントの比率について厳密な規則はなく、コードの一部 (正規表現など) にはコードよりも多くのコメントが含まれる場合があります。
最も重要な習慣ですが、従うのが最も難しい習慣は、コメントを最新の状態に保つことです。古いコメントは、まったくコメントしないよりも誤解を招くためです。
著者について
Stoyan Stefanov は、Yahoo! Web 開発者、著者、寄稿者、およびオライリーの書籍の技術評論家です。彼は、カンファレンスや www.phpied.com のブログで Web 開発のトピックについて頻繁に講演しています。 Stoyan は、smush.it 画像最適化ツールの作成者でもあり、YUI の貢献者でもあり、Yahoo のパフォーマンス最適化ツール YSlow 2.0 のアーキテクトでもあります。
この記事は次から転載されています: http://www.zhangxinxu.com/wordpress/?p=1173
英語の原文: http://net.tutsplus.com/tutorials/javascript-ajax/the-ライティングの要点 - 高品質 JavaScript/
同期と結論
この記事はディレクトリ インデックスに同期されています: JavaScript を深く理解するシリーズ
詳細JavaScript の理解 一連の記事(オリジナル作成、翻訳、転載を含む) その他の種類の記事が役に立ちましたら、おじさまの書くモチベーションにつながるよう、お勧めしたり、サポートしたりしてください。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。