『JavaScriptモード』読書ノート(4)—関数2

12939 ワード

このページでは、関数の勉強を続けています.
 
二、コールバックモード
関数はすべてオブジェクトです.これらはパラメータとして他の関数に渡すことができます.
function writeCode(callback) {
    //       ...
    callback();
    // ...
}
function introduceBugs() {
    // ...    
}

writeCode(introduceBugs);
introuduceBugs()はパラメータとしてwriteCodeに渡す時は括弧がないので注意してください.括弧は関数を実行することを表していますが、この場合、私達は関数のアプリケーションを伝達するだけで、適切な時にそれを実行させます.
 
コールバックの例
いくつかの複雑な論理を実行した後、バルクデータの結果を返す必要があると仮定した例を示した.
var findNodes = function() {
    var i = 100000,//        
        nodes = [],//     
        found;//         
    while(i) {
        i -= 1;
        //         ...
        nodes.push(found);
    }
    return nodes;
}
関数の汎用性を維持し、実際の要素に対して何の処理も行わずにDOMノード配列に戻すことは非常に良い考えです.ノードの論理を変更することは、他の関数で実施されてもよい.
var hide = function (nodes){
    var i = 0,max = nodes.length;
    for(;i < max;i += 1) {
        nodes[i].style.display = "none";
    }
};

//     
hide(findNodes());
上記の実現方式は非効率です.hide()は、再びfindNodes()によって返される配列ノードを巡回しなければならないからである.このようなループを回避することができ、かつ、findNodes()においてノードを隠すことができるなら、これは効率的な実施形態である.しかし、もしfindNodes()に隠し論理が実現されたら、論理結合の検索と修正のため、もはや汎用関数ではない.このような問題に対する解決方法は、コールバックモードを採用しており、ノードをコールバック関数としてfindNodesに伝達し、実行を依頼することができる.
    //   findNodes()         
var findNodes = function(callback) {
    var i = 100000,//        
        nodes = [],//     
        found;//         

    //              
    if(typeof callback !== "function") {
        callback = false;
    }

    while(i) {
        i -= 1;
        //         ...
        //         
        if(callback){
            callback(found);
        }
        nodes.push(found);
    }
    return nodes;
}
これは非常に直接的な実現方法である.findNodes()が実行する唯一の追加タスクは、オプションのコールバック関数が提供されているかどうかを確認し、存在すれば実行します.この中で、コールバック関数はオプションですので、再構成されたfindNodes()は以前のように使用できます.
今、hide()の実現は、すべてのノードを遍歴する必要がないからです.
var hide = function (node){
    node.style.display = "none";
};

//     
findNodes(hide);
上記のように、コールバック関数は既存の関数であっても良いし、匿名の関数であっても良いし、メイン関数を呼び出したときに作成することができます.例えば、以下のコードは、ノードを表示するために同じfindNodes()関数をどのように使用するかを示している.
//        
findNodes(function(node) {
    node.style.display = "block";
});
 
コールバックとスコープ
前の例では、コールバック実行の文の部分は以下のようになっています.
callback(parameters);
ほとんどの場合、この方法は単純で効果的であるが、一度の匿名関数またはグローバル関数ではなく、対象の方法である場合が多い.このコールバック方法がthisを使用して彼の所属するオブジェクトを引用すると、思わぬ行動が発生する可能性があります.
//   findNodes()         
var findNodes = function(callback) {
    var i = 100000,//        
        nodes = [],//     
        found;//         

    //              
    if(typeof callback !== "function") {
        callback = false;
    }

    while(i) {
        i -= 1;
        //         ...
        //         
        if(callback){
            callback(found);
        }
        nodes.push(found);
    }
    return nodes;
}
//        

var myapp = {};
myapp.color = "green";
myapp.paint = function(node) {
    node.style.color = this.color;
};
findNodes(myapp.paint)
もしあなたが本当にそうすれば、彼は予想通りには実行しないはずです.これは、this.co lorが定義されていないからです.findNodes()はグローバル関数であるため、thisはグローバルオブジェクトを指しています.同様に、findNodes()がdomというオブジェクトの方法である場合(dom.findNodes)、内部のthisはmyppではなくdomを指します.
この問題に対する解決策は伝達コールバック関数であり、さらにこのコールバック関数が属するオブジェクトを伝達する.
findNodes(myapp.paint,myapp);
そしてもちろん、転送されたオブジェクトを結合するために、findNodes()を変更する必要がある.
 
var findNodes = function(callback,callback_obj) {
    // ...
    if(typeof callback === 'function') {
        callback.call(callback_obj,found);
    }
    // ...
};
私たちはコールを使っています.あとで詳しい説明をします.
上記の方法は、オブジェクトの名前を2回入力する必要がなく、少し最適化できます.
findNodes('paint',myapp);
そして、findNodes()の内部にはちょっと小さな変動があります.
var findNodes = function(callback,callback_obj) {
    //            
    if(typeof callback === 'string') {
        callback = callback_obj[callback];
    }
    // ...
    if(typeof callback === 'function') {
        callback.call(callback_obj,found);
    }
    // ...
};
 
非同期事件の傍受
コールバックモードには多くの一般的な用途があります.例えば、イベントモニターをページ上の要素に追加すると、実際にコールバック関数ポインタが提供されます.以下は簡単な例であり、ドキュメントのクリックイベントを監視するときに、どのようにコールバック関数consolie.log()を伝達するかを示している.
document.addEventListener("click", console.log, false);
ほとんどのクライアントブラウザのプログラミングはイベント駆動です.例えば、ページローディングが完了するとロードイベントが発生し、ユーザーとページの相互作用が発生すると、例えば、click、keypes、mouseover、mousemommoveなどがトリガされます.JavaScriptは特にイベントドライバのプログラミングに適しています.コールバックモードはプログラムを非同期的に実行しています.つまり、順序を乱して実行できます.
 
タイムアウト
コールバックモードを使用する別の例は、ブラウザのwindowオブジェクトを使用して提供されるタイムアウト方法:setTimeout()とset Interval()である.これらの方法はまた、コールバック関数を受け入れて実行します.
var thePlotThickens = function() {
    console.log("500ms later...");
};

setTimeout(thePlotThickens,500);
ここで関数the PlotThickensはどのように変数で伝達されていますか?この関数を伝える時は括弧を持っていません.関数をすぐに実行したくないので、setTimeout()は後で使うために関数を指したいだけです.
 
ライブラリのコールバックモード
コールバックモードは簡単で強力なモデルです.倉庫を設計する時に彼は役に立ちます.ソフトウェアライブラリに入るコードは、可能な限り汎用および使用可能なコードであるべきです.このようなユニバーサル化を実現するためには、コールバックが役立ちます.予想と実現が必要ではない各機能は、ライブラリを急速に膨張させるため、大多数のユーザーは永遠にその中の大量の機能を必要としない.対照的に、コア機能に集中し、「フック」形式のコールバック関数を提供することができます.これは簡単に構築、拡張され、ユーザー定義のライブラリ方法となります.
 
三、戻り関数
関数もオブジェクトですので、戻り値としても使用できます.この関数は、実行結果として何らかのデータ値またはデータ配列で返す必要がないことを示しています.関数は他のより専門的な関数を返してもいいし、必要に応じて別の関数を作成してもいいです.これはその入力に依存します.
  
var setup = function () {
    alert(1);
    return function() {
        alert(2);
    };
};

//   setup  
var my = setup(); // alerts 1
my(); // alerts 2

//   setup()       ,        ,                ,
//                ,          。
//            ,         ,          :

var setup1 = function() {
    var count = 0;
    return function () {
        return (count += 1);
    };
};
//   
var next = setup1();
console.log(next());
console.log(next());
console.log(next());
  
この記事は主にコールバック関数とリターン関数を紹介しています.この2つは実際の開発において非常に価値があります.ぜひ真剣に見てください.次のページでは、ユーザー定義関数とインスタント関数を学習します.