JavaScriptの解説書で「関数は自分自身を呼び出せる」という記述を見かけます。

 

例えば「特定のファイルを指定されたフォルダの中から検索する」方法を考えてみます。まず、あまり深く考えずに以下のようなコードを試してみます。

//任意のファイルを指定されたフォルダから探す
function findFile(fdObj,fName) {
    var fList = fdObj.getFiles(); //フォルダの内容を全て取得
    var L=fList.length //内容物の数
    for (var i=0; i<L; i++) {
        if( !(fList[i] instanceof Folder) ) { //フォルダでなければ...
            //ファイル名が一致していたらそれを返す
            if ( fList[i].name===fName ) {return fList[i];}
        }
    }
    return null; //見つからなければnullを返す
}
//ここから実行
var folderObj = Folder.selectDialog("検索するフォルダを選択"); //フォルダ選択ダイアログ
if ( folderObj === null) {exit();} //キャンセル処理
var fileName = prompt("検索したいファイル名を入力"); //ファイル名入力ウィンドウ
var res = findFile(folderObj,fileName); //関数呼び出し
if ( res===null ) { //返り値が...
    //nullなら
    alert("見つかりませんでした");
}else{
    //nullでなければ
    alert(res); //ファイルパスを表示
}

この例ではフォルダ内の内容を配列として取り出し、把握した数のぶんだけfor文でファイル名を評価しています。検索対象はファイルだけとし、内容がフォルダだった場合は判定処理を飛ばしています。

 

1階層のみの検索であればこれでよいでしょう。しかし、内包されているフォルダの中も検索対象にしたい場合、IF文で「フォルダを見つけた時」という処理のネスト(入れ子状態)を何回用意すればよいかが問題になります。

ファイルの検索を行う前に、ディレクトリ構造を把握するためのプリスキャンを行うという方法はありますが、これだと全く同じファイルアクセスを2回行うことになり、いかにも効率的ではありません。

 

このようなときに「関数自身を呼び出せる」という仕様が重宝します。

 

それほど面倒なことではありません。フォルダに行き当たったら単純に自分自身を呼び出すだけで、コードの書き換えはたった2行だけです。

//任意のファイルを指定されたフォルダから探す(多階層)
function findFile(fdObj,fName) {
    var fList = fdObj.getFiles(); //フォルダの内容を全て取得
    var L=fList.length //内容物の数
    for (var i=0; i<L; i++) {
        if( fList[i] instanceof Folder ) { //フォルダなら...
            var res = findFile(fList[i],fName); //<---ここが再帰的呼び出し
            if ( res !==null ) {return res;} //返り値がnullでなければそれを返す
        }
        //ファイル名が一致していたらそれを返す
        if ( fList[i].name===fName ) {return fList[i];}
    }
    return null; //見つからなければnullを返す
}
//ここから実行
var folderObj = Folder.selectDialog("検索するフォルダを選択"); //フォルダ選択ダイアログ
if ( folderObj === null) {exit();} //キャンセル処理
var fileName = prompt("検索したいファイル名を入力"); //ファイル名入力ウィンドウ
var res = findFile(folderObj,fileName); //関数呼び出し
if ( res===null ) { //返り値が...
    //nullなら
    alert("見つかりませんでした");
}else{
    //nullでなければ
    alert(res); //ファイルパスを表示
}

 

より実践的に書くのなら以下のようになります。これは「異なる階層に同名のファイルが複数存在する可能性」に考慮したものです。

//任意のファイルを指定されたフォルダから探す(多階層・同名ファイル名対応)
function findFile(fdObj,fName) {
    var rList=[]; //返り値用の配列
    var fList = fdObj.getFiles(); //フォルダの内容を全て取得
    var L=fList.length //内容物の数
    for (var i=0; i<L; i++) {
        if( fList[i] instanceof Folder ) { //フォルダなら...
            var res = findFile(fList[i],fName); //再帰的呼び出し
            rList=rList.concat(res); //返り値を配列に加える(配列の結合)
        }
        //ファイル名が一致していたら配列に追加
        if ( fList[i].name===fName ) {rList.push(fList[i]);}
    }
    return rList; //配列を返す
}
//ここから実行
var folderObj = Folder.selectDialog("検索するフォルダを選択"); //フォルダ選択ダイアログ
if ( folderObj === null) {exit();} //キャンセル処理
var fileName = prompt("検索したいファイル名を入力"); //ファイル名入力ウィンドウ
var resList = findFile(folderObj,fileName); //関数呼び出し
if ( resList.length===0 ) { //返り値の配列が...
    //0なら
    alert("見つかりませんでした");
}else{
    //0でなければ
    alert(resList); //ファイルパスを表示
}

 

 

Joomla templates by a4joomla