ホームページ  >  記事  >  ウェブフロントエンド  >  高品質なJSコードの書き方_基礎知識

高品質なJSコードの書き方_基礎知識

WBOY
WBOYオリジナル
2016-05-16 16:23:541019ブラウズ

効率的な JavaScript ライブラリを作成したいのですが、どうやって始めればよいのかわかりません。

他の人のクラスライブラリを読んでみましたが、理解できたようです

js の高度な機能を勉強するつもりですが、権威のある本の内容があまりにも散らかっていて、

「使い方」は覚えていても、「使う」となると「方法」は考えません。

あなたも私と同じかもしれません。目に見えない力が私たちの計画を制限し、私たちに知識の限界について繰り返し考えさせ、立ち止まって前進するのが難しいように感じさせます。

この期間中、さまざまな課題、コース設計、実験レポートのせいでプレッシャーは倍増しました。自分のクラス ライブラリの作成に少しでも近づくために、少しの時間を費やし、決して寝ずに、過去に読んだ本を整理して要約することはめったにありません。

この記事では、「JavaScript 言語のエッセンス」と「効果的な JavaScript」について説明します。例はデバッグされており、それらを理解した後、いくつかの「奥深い」原則をもう少し単純化したいと思います。

1. 変数のスコープ

プログラマーにとってスコープは酸素のようなものです。それはどこにでもありますが、多くの場合、それについて考えさえしません。しかし、それが汚染されている場合 (例: グローバル オブジェクトの使用)、息苦しく感じることがあります (例: アプリケーションの応答性が低下する)。 JavaScript の中核となるスコープ規則は、シンプルで、うまく設計されており、強力です。 JavaScript を効果的に使用するには、変数スコープのいくつかの基本概念を習得し、とらえどころのない厄介な問題につながる可能性のあるいくつかの特殊なケースを理解する必要があります。

1.1 グローバル変数の使用はできるだけ少なくする

JavaScript を使用すると、グローバル名前空間で変数を簡単に作成できます。グローバル変数の作成は、いかなる形式の宣言も必要とせず、プログラム全体のすべてのコードによって自動的にアクセスされるため、簡単に作成できます。

私たちのような初心者にとって、特定のニーズ(たとえば、送信されたデータを記録する、特定の関数が特定の時間に呼び出されるのを待つときに使用する、または特定の関数が頻繁に使用される)に遭遇した場合、グローバル関数について考えることさえ躊躇します。1 年生のときに学んだ C 言語はプロセス指向の考え方に深く根付いており、システムはきちんと関数でいっぱいです。グローバル変数を定義すると、共有パブリック名前空間が汚染され、予期しない名前の競合が発生する可能性があります。グローバル変数は、プログラム内の独立したコンポーネント間の不必要な結合につながるため、モジュール性にも悪影響を及ぼします。真剣に言うと、グローバル (div または a のスタイルを直接定義するスタイル シートを含む) が多すぎると、複数人による開発プロセスに統合されたときに致命的なエラーが発生します。そのため、jQuery のコードはすべて、すぐに実行される匿名式 (自己呼び出し型匿名関数) でラップされています。ブラウザーが jQuery ファイルをロードすると、自己呼び出し匿名関数がすぐに実行を開始し、グローバル変数の損傷や汚染、他のコードへの影響を避けるために jQuery の各モジュールを初期化します。

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

(関数(ウィンドウ,未定義){
var jQuery = ...
//...
window.jQuery = window.$ = jQuery;
})(ウィンドウ);

また、「最初に好きなように書いて、後で整理する」方が便利だと思うかもしれませんが、優れたプログラマーは常にプログラムの構造に注意を払い、関連する機能を分類し、無関係なコンポーネントを分離し続けます。 . これらの動作をプログラミング プロセスの一部として含めます。

グローバル名前空間は JavaScript プログラム内の独立したコンポーネントが対話する唯一の方法であるため、グローバル名前付きコントロールの使用は避けられません。コンポーネントまたはライブラリは、いくつかのグローバル変数を定義する必要があります。プログラムの他の部分で使用するため。それ以外の場合は、ローカル変数を使用することをお勧めします。

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

this.foo ;//未定義
foo = "グローバル foo";
this.foo ;//「グローバル foo」
var foo = "グローバル foo";
this.foo = "変更されました";
foo ;//変更されました

JavaScript のグローバル名前空間は、プログラムのグローバル スコープでアクセス可能なグローバル オブジェクトにも公開されており、this キーワードの初期値として機能します。 Web ブラウザでは、グローバル オブジェクトはグローバル ウィンドウ変数にバインドされます。これは、グローバル変数を作成するには 2 つの方法があることを意味します。グローバル スコープで var を使用して宣言するか、グローバル オブジェクトに追加します。 var 宣言を使用する利点は、プログラム スコープ内のグローバル変数の影響を明確に表現できることです。

バインドされたグローバル変数への参照が実行時エラーを引き起こす可能性があることを考慮すると、スコープを明確かつ簡潔に保つことで、コードのユーザーがプログラムで宣言されているグローバル変数を理解しやすくなります。

グローバル オブジェクトはグローバル環境に対する動的な応答メカニズムを提供するため、これを使用して実行環境をクエリし、このプラットフォームで利用可能な機能を検出できます。

eg.ES5 では、JSON 形式でデータを読み書きするためのグローバル JSON オブジェクトが導入されています。

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

if(!this.JSON){
This.JSON = {
解析: ..,
文字列化: ... }
}

JSON 実装を提供する場合、もちろん、独自の実装を簡単かつ無条件に使用できます。ただし、ホスティング環境によって提供される組み込み実装は、ブラウザーに C で記述されるため、ほとんどより適切です。なぜなら、それらは特定の標準に照らして正確性と一貫性が厳密にチェックされており、一般にサードパーティの実装よりも優れたパフォーマンスを提供するからです。

データ構造コースの元の設計では、文字列の基本操作をシミュレートしており、言語自体が提供するメソッドを使用することはできませんでした。 JavaScript は配列に対する基本的な操作を非常に適切に実装しています。一般的な学習ニーズだけであれば、言語自体が提供するメソッドをシミュレートするという考えは良いことですが、本当に開発に投資するのであれば、その必要はありません。まず JavaScript の組み込みメソッドを使用することを検討してください。

1.2 との併用を避ける

with ステートメントは、アプリケーションの信頼性を低下させ、非効率にする「利便性」を提供します。単一のオブジェクトに対して一連のメソッドを順番に呼び出す必要があります。 with ステートメントを使用すると、オブジェクトへの繰り返しの参照を簡単に回避できます:

コードをコピーします コードは次のとおりです:
関数ステータス(情報){
var widget = new Widget();
with(ウィジェット){
setBackground("blue");
setForeground("white");
setText("ステータス : " info);
show();
}
}

with ステートメントを使用してモジュール オブジェクトから変数を「インポート」することも誘惑されます。

コードをコピーします コードは次のとおりです:
関数 f(x,y){
with(数学){
return min(round(x),sqrt(y));//抽象参照
}
}

実際、JavaScript はすべての変数を同じように扱います。 JavaScript は、最も内側のスコープから始めて外側に向かって変数を探します。 with 言語は、オブジェクトを変数スコープを表すかのように扱うため、with ブロック内での変数検索は、指定された変数名のプロパティを検索することから始まります。このオブジェクトでプロパティが見つからない場合は、外側のスコープで検索が続行されます。 with ブロック内の外部変数への参照はすべて、with オブジェクト (およびそのプロトタイプ オブジェクト) 内に同じ名前のプロパティが存在しないことを暗黙的に前提としています。プログラム内の他の場所で with オブジェクトまたはそのプロトタイプ オブジェクトを作成または変更する場合は、必ずしもこの仮定に従っているとは限りません。もちろん、JavaScript エンジンは、使用されているローカル変数を見つけるためにローカル コードを読み取りません。 JavaScript スコープは効率的な内部データ構造として表すことができ、変数の検索は非常に高速になります。ただし、with コード ブロックは、with コード内のすべての変数を見つけるためにオブジェクトのプロトタイプ チェーンを検索する必要があるため、その実行速度は通常のコード ブロックよりもはるかに遅くなります。

言語を使用する代わりに、オブジェクトを短い変数名にバインドする簡単な方法です。

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

関数ステータス(情報){
var w = 新しいウィジェット();

w.setBackground("青");
w.setForeground("白");
w.setText("ステータス : " info);
w.show();

}

他のケースでは、ローカル変数を関連するプロパティに明示的にバインドすることが最善の方法です。

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

関数 f(x,y){
var min = Math.min,
Round = Math.round,
sqrt = Math.sqrt; min(round(x),sqrt(y));
を返す }

1.3 クロージャに熟練している

クロージャを理解するための概念は 1 つあります。

a) JavaScript を使用すると、現在の関数の外部で定義された変数を参照できます。

コードをコピーします コードは次のとおりです:
関数 makeSandwich(){
var magicIngredient = "ピーナッツバター";
関数 make(fill){
return magicIngredient " および "filling;
}
make("ゼリー") を返します
}
makeSandwich();// 「ピーナッツバターとゼリー」

b) 外部関数が戻った場合でも、現在の関数は外部関数 で定義された変数を参照できます。

コードをコピーします コードは次のとおりです:
関数 makeSandwich(){
var magicIngredient = "ピーナッツバター";
関数 make(fill){
return magicIngredient " および "filling;
}

を返します }
var f = SandwichMaker();
f ("ゼリー") // "ピーナッツバターとゼリー"
f("バナナ"); // "ピーナッツバターとバナナ"
f("アオイ科"); // "ピーナッツバターとアオイ科"

javascriptd の関数値には、呼び出し時に実行するために必要なコードよりも多くの情報が含まれています。さらに、JavaScript 関数の値は、それを囲むスコープ内で定義されている、参照する可能性のある変数も内部的に格納します。対象範囲内の変数を追跡する関数はクロージャと呼ばれます。

make 関数はクロージャであり、そのコードは 2 つの外部変数、magicIngredient と filling を参照します。クロージャはこれら 2 つの変数を格納するため、make 関数が呼び出されるたびに、そのコードはこれら 2 つの変数を参照できます。

関数は、パラメーターや外部関数変数など、そのスコープ内の任意の変数を参照できます。これを利用して、より一般的な SandwichMaker 関数を作成できます。

コードをコピーします コードは次のとおりです:
function makeSandwich(magicIngredient){
関数 make(fill){
return magicIngredient " および "filling;
}

を返す }
var f = SandwichMaker("ハム");
f("チーズ"); // "ハムとチーズ"
f("マスタード"); // "ハムとマスタード"

クロージャは JavaScript の最もエレガントで表現力豊かな機能の 1 つであり、多くのイディオムの中心となっています。

c) クロージャは外部変数の値を更新できます。 実際、クロージャは外部変数の値のコピーではなく、外部変数への参照を保存します。したがって、これらの外部変数にアクセスできるクロージャに対して更新を行うことができます。

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

関数ボックス(){
var val = 未定義;
戻り値 {
set: function(newval) {val = newval;},
get: function (){return val;},
type: function(){return typeof val;}
};
}
var b = box();
b.type(); //未定義
b.set(98.6);
b.get();//98.6
b.type();//数値

この例では、3 つのクロージャを含むオブジェクトを生成します。これら 3 つのクロージャは set、type、get プロパティであり、すべて val 変数へのアクセスを共有します。set クロージャは val の値を更新します。次に、get と type を呼び出して、更新された結果を表示します。

1.4 変数宣言の改善点を理解する

JavaScript は、このスコープ方法をサポートしています (変数 foo への参照は、foo 変数の宣言に最も近いスコープにバインドされます) が、ブロックレベルのスコープはサポートしていません (変数定義のスコープは、最も近い囲みスコープ) ステートメントまたはコードのブロック)。

この機能を理解していないと、いくつかの微妙なバグが発生する可能性があります:

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

関数 isWinner(プレイヤー,その他){
var 最高値 = 0;
for(var i = 0,n = other.length ;i var player = other[i];
If(プレイヤースコア > 最高値){
最高= player.score; }
}
player.score を返します >
}

1.5 名前付き関数式の扱いにくいスコープに注意してください

コードをコピーします コードは次のとおりです:
関数 double(x){ return x*2 }
var f = function(x){ return x*2 }

同じ関数コードを式として使用することもできますが、意味はまったく異なります。匿名関数と名前付き関数式の正式な違いは、後者は関数のローカル変数として同じ関数名の変数にバインドされることです。これを使用して再帰関数式を作成できます。

コードをコピーします コードは次のとおりです:
var f = 関数 find(tree,key){
//....
find(tree.left, key) を返す ||
find(tree.right,key); }


変数 find のスコープは、関数宣言とは異なり、その関数内のみであることに注意してください。名前付き関数式は、内部関数名を通じて外部から参照できません。

コードをコピーします コードは次のとおりです:
find(myTree,"foo");//エラー: 検索が定義されていません。
var コンストラクター = function(){ null を返す }
var f= function(){
コンストラクターを返します();
};
f();//{}(ES3 環境の場合)

このプログラムは null を生成するように見えますが、実際には新しいオブジェクトを生成します。

名前付き関数変数のスコープは Object.prototype.constructor (つまり、Object のコンストラクター) を継承するため、with ステートメントと同様に、このスコープは Object.prototype の動的な変更の影響を受けます。オブジェクトがシステム内の関数式のスコープを汚染することを避ける方法は、常に Object.prototype にプロパティを追加しないようにし、標準の Object.prototype プロパティと同じ名前のローカル変数を使用しないようにすることです。

一般的な JavaScript エンジンのもう 1 つの欠点は、名前付き関数式の宣言が促進されることです。

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

var f = function g(){return 17;}
g(); //17 (非準拠環境の場合)

一部の JavaScript 環境では、2 つの関数 f と g が異なるオブジェクトとして扱われるため、不必要なメモリ割り当てが発生します。

1.6 ローカル ブロック関数の扱いにくいスコープ宣言に注意してください

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

関数 f() {「グローバル」を返す }
; 関数テスト(x){
関数 f(){return "ローカル";}
var result = [];
If(x){
result.push(f());
}
result.push(f());
結果結果;
}
test(true); //["ローカル","ローカル"]
test(false); //["ローカル"]

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

関数 f() {「グローバル」を返す }
; 関数テスト(x){
var result = [];
If(x){
function f(){return "local";}
result.push(f());
}
result.push(f());
結果結果;
}
test(true); //["ローカル","ローカル"]
test(false); //["ローカル"]

JavaScript にはブロックレベルのスコープがないため、内部関数 f のスコープはテスト関数全体である必要があります。これは一部の JavaScript 環境に当てはまりますが、すべての JavaScript 実装が厳密モードでこのような関数をエラーとして報告するわけではありません (ローカル ブロック関数宣言を持つ厳密モードのプログラムは、構文エラーとして報告します)。 -移植可能なコードを作成し、標準の将来のバージョンのローカル ブロック関数宣言に、より賢明で信頼性の高いセマンティクスを提供します。この状況では、グローバル関数 f を指すテスト関数でローカル変数を宣言することを検討できます。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。