ホームページ  >  記事  >  ウェブフロントエンド  >  高品質なJSコードの書き方(続き)_JavaScriptスキル

高品質なJSコードの書き方(続き)_JavaScriptスキル

WBOY
WBOYオリジナル
2016-05-16 16:13:201205ブラウズ

前回の記事「高品質なJSコードの書き方」に引き続き、今回はJavaScriptの関数の知識点を整理していきます。

2. 関数

を使用します。

関数は、プログラマに主要な抽象関数と実装メカニズムを提供します。関数は、プロシージャ、メソッド、コンストラクター、さらにはクラスやモジュールなど、他の言語のいくつかの異なる機能を独立して実装できます。

2.1 関数呼び出し、メソッド呼び出し、コンストラクター呼び出しの違いを理解する

オブジェクト指向プログラミングの場合、関数、メソッド、クラス コンストラクターは 3 つの異なる概念です。

使用モード:

1、関数呼び出し

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

関数 hello(ユーザー名){
「hello」ユーザー名を返します;
}

2、メソッド呼び出し

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

var obj = {
こんにちは: function(){
return "hello, " this.username;
}、
ユーザー名: "floraLam"
};
ohj.hello();//「こんにちは、フローララム」

hello メソッドが obj オブジェクトで定義されているため、この変数はオブジェクトにバインドされています。同じ関数参照を別のオブジェクトに割り当てても、同じ答えが得られます。

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

var obj2 = {
こんにちは: obj.hello(),
ユーザー名: "floraLam"
};

3、コンストラクターは

を使用します

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

関数 User(名前,パスワードハッシュ){
This.name = 名前;
This.passwordHash = パスワードハッシュ;
}

new 演算子を使用して User を呼び出すことは、コンストラクターとみなされます。

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

var u = 新しいユーザー("floraLam","123");

関数呼び出しやメソッド呼び出しとは異なり、コンストラクター呼び出しは、この変数の値として新しいオブジェクトを使用し、この新しいオブジェクトを呼び出し結果として暗黙的に返します。コンストラクターの主な役割は、この新しいオブジェクトを初期化することです。

2.2 高階関数に精通している

高階関数は、関数をパラメーターとして受け取るか、値を返す関数にすぎません (高階関数がそれを「呼び出す」ため、コールバック関数と呼ばれることがよくあります)。特に強力で表現力豊かな方法であるイディオムは、js プログラムでも広く使用されています。

配列の標準ソート メソッドを考えてみましょう。すべての配列で機能するには、ソート メソッドは配列内の 2 つの要素を比較する方法を呼び出し元で決定する必要があります。

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

関数compareNumber(x,y){
If(x return -1;
}
If(x > y){
1 を返します;
}
0 を返す;
}
[3,1,4,1,5,9].sort(compareNumbers);//[1,1,3,4,5,9]

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

[3,1,4,1,5,9].sort(function(x,y){
If(x return -1;
}
If(x > y){
1 を返します;
}
0 を返す;
});//[1,1,3,4,5,9]

上記の例は、匿名関数を使用してさらに簡略化されています。

高階関数の使い方を学ぶと、コードが簡素化され、退屈な定型コードが不要になることがよくあります。ループを使用して文字列配列の単純な変換を実装できます:

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

var names = ["フレッド","ウィルマ","ペブルズ"];
var upper = [];
for(var i = 0,n = names.length ;i upper[i] = names[i].toUpperCase();
}
upper;//["フレッド","ウィルマ","ペブルズ"];

配列の便利なマップメソッドを使用すると、ループを排除し、ローカル関数を使用して要素を 1 つずつ変換するだけです。

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

var names = ["フレッド","ウィルマ","ペブルズ"];
var upper = names.map(関数(名前){
name.toUpperCase();
を返します });
upper;//["フレッド","ウィルマ","ペブルズ"];

さらに、たとえば、共通の実装ロジックで異なる文字列を作成するメソッドをいくつか作成し、各ループで独立した各部分の計算結果を連結して文字列を作成したいとします。

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

関数 bulidString(n,callback){
var result = "";
for(var i = 0 ; i 結果 = callback(i);
}
結果を返します;
}
var alphabet = bulidString(26,function(i){
戻り値 String.fromCharCode(aIndex i);
});
アルファベット;//"abcdefghijklmnopqrxtuvwxyz";
var 数字 = buildString(10,function(i){ return i;})
数字;//"0123456789"
var ランダム = buildString(9,function(){
Random = String.fromCharCode(Math.floor(Math.random()*26) aIndex
});
ランダム;//"yefjmcef"(ランダム)

これにより、読者は実装の詳細に立ち入ることなく、コードで何ができるかをより明確に理解できるようになります。

備考

JavaScript は、指定された範囲 (m-n の間) の乱数の式を返します: Math.random()*(n-m) m

同時に、質問の要件と正の整数を返す必要があるかどうかにも注意してください

2.3 通話モード

関数を呼び出すと、現在の関数の実行が一時停止され、制御とパラメータが新しい関数に渡されます。 宣言時に定義された仮パラメータに加えて、各関数は 2 つの新しい追加パラメータ (this と argument) を受け取ります。

これは非常に重要なパラメータであり、その値は呼び出しモードによって決まります。

JavaScript における 4 つの重要な呼び出しパターンは次のとおりです:

a. メソッド呼び出しパターン
b. 関数呼び出しパターン
c. コンストラクター呼び出しパターン
d. 適用呼び出しパターンを適用します

これらのモードは、キーパラメータの初期化方法が異なります

1. メソッド呼び出しメソッド

関数がオブジェクトのメソッドとして機能する場合、その関数をメソッドと呼びます。メソッドが呼び出されると、メソッドは呼び出し元のオブジェクトにバインドされます。

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

var myObj={
val:0、
インクリメント:関数(inc){
This.val =typeof inc ==="number"? inc:1;
}、
Get_val:function(){この val を返す;}
}
myObj.increment();// 1
myObj["増分"](2);//3

概要:

1. これを通じて、オブジェクトが属するオブジェクトのコンテキストを取得できるメソッドは、パブリック メソッドと呼ばれます

2. . または添え字式を使用して関数を使用する場合、それはメソッド呼び出しモードであり、このオブジェクトは前のオブジェクトにバインドされます。

3. 関数はこれを使用してオブジェクトにアクセスし、オブジェクトの値を取得したり、オブジェクトの値を変更したりできます。これをオブジェクトにバインドするのは呼び出し時に行われます。

2. 関数呼び出しパターン

関数がオブジェクトのプロパティではない場合、関数として呼び出されます。関数呼び出しモードで関数を呼び出すと、グローバルオブジェクトにバインドされます。これは JavaScript の設計ミスであり、今も続いています。

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

関数 add(x,y){
x y を返します;
}
myObj.double=function(){
var that=this;
var helper=function(){
That.val=add(that.value,that.value);
//間違った書き方はこうかもしれませんが、なぜ間違っているのでしょうか?関数が内部関数として呼び出された場合、これは間違ったオブジェクトにバインドされており、グローバル オブジェクトには val 属性がないため、間違った値が返されます。
//this.val = this.val this.val;
}
ヘルパー();
}
myObj.double();//6

3. コンストラクターの呼び出しパターン

JavaScript はプロトタイプ継承に基づいた言語です。つまり、オブジェクトは他のオブジェクトからプロパティを直接継承でき、言語はクラスレスです。

先頭に new を付けて関数を呼び出すと、関数に接続されているプロトタイプ メンバーを非表示にする新しいオブジェクトが取得され、これも新しいオブジェクトにバインドされます。

新しい接頭辞により、return ステートメントの動作も変更されます。これも推奨されるプログラミング方法ではありません。

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

var Foo = 関数(ステータス){
This.status = ステータス;
}
Foo.prototype.get_status = function(){
this.status を返します;
}
//Foo インスタンスを構築します
var myFoo = new Foo("bar");
myFoo.get_status();//"バー"

4. 適用呼び出しパターンを適用します

JavaScript は関数型オブジェクト指向言語であるため、関数にはメソッドを含めることができます。

Apply メソッドには 2 つのパラメータがあり、1 つ目はこれにバインドされる値で、2 つ目はパラメータ配列です。つまり、Apply メソッドを使用すると、配列を構築し、それを使用して関数を呼び出すことができます。これにより、この値を選択することができます。この値により、配列の値を選択することもできます。

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

var 配列 = [3,4];
var sum = add.apply(null,array) // 7
; var statusObj = {ステータス:"ABCDEFG"};
Foo.prototype.pro_get_status = function(prefix){
プレフィックス「-」を返します。this.status;
}
var status = Foo.prototype.get_status.apply(statusObj);// "ABCDEFG"
var pro_status = Foo.prototype.get_status.apply(statusObj,["prefix"]);// "prefix -ABCDEFG"

通常、関数またはメソッドの受信者 (特別なキーワード this にバインドされた値) は呼び出し元の構文によって決まります。特に、メソッド呼び出し構文はメソッド オブジェクトを this 変数にバインドします。ただし、関数を呼び出すためにカスタム レシーバーを使用する必要がある場合があります。このとき、callメソッドまたはbindメソッドを使用して、メソッド

を呼び出すようにレシーバーをカスタマイズする必要があります。

2.4 バインド メソッドを使用して、決定された受信者を持つメソッドを抽出する

値が関数であるメソッドとプロパティに違いはないので、オブジェクトのメソッドを抽出したり、関数をコールバック関数として抽出して高階関数に直接渡すことも簡単です。

しかし、抽出された関数のレシーバーを関数の抽出元のオブジェクトにバインドすることも忘れがちです。

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

var バッファ = {
エントリ: []、
:function(s){
を追加 This.entries.push(s);
}
}
var ソース = ["867","-","5309"];
source.forEach(butter.add);//error:entries が未定義です

現時点では、butter.add の受信者は Butter オブジェクトではありません。関数のレシーバーは呼び出し方法によって異なります。forEach メソッドはグローバル スコープで呼び出されるため、グローバル オブジェクトにはエントリ属性がないため、forEach メソッドの実装ではグローバル オブジェクトがデフォルトのレシーバーとして使用されます。コードスロー エラーが発生しました。

forEach メソッドを使用すると、呼び出し元はコールバック関数の受信者としてオプションのパラメーターを提供できます。

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

var ソース = ["867","-","5309"];
source.forEach(butter.add,butter);

しかし、すべての高階関数がユーザーにコールバック関数レシーバーを提供できるほど十分に配慮されているわけではありません。

解決策は 2 つあります:

1) バッファー オブジェクト メソッドを介して add を明示的に呼び出すラッパー関数を作成します。ラップされた関数がどのように呼び出されるかに関係なく、そのパラメーターがターゲット配列にプッシュされることが常に保証されます。

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

var ソース = ["867","-","5309"];
source.forEach(関数{
Butter.add(s);
});

2) 関数オブジェクトのバインドメソッドはレシーバーオブジェクトを必要とし、レシーバーオブジェクトのメソッド呼び出しを利用して元の関数を呼び出すラッパー関数を生成します。

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

var ソース = ["867","-","5309"];
source.forEach(butter.add.bind(buffer));

備考

buffer.add.bind(buffer) は、buffer.add 関数を変更する代わりに新しい関数を作成します。

buffer.add ===buffer.add.bind(buffer); //false

以上がこの記事の全内容です。皆さんに気に入っていただければ幸いです。

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