JS・WSHで配列の便利関数のライブラリ案


並んでいるデータを処理する時は,必ずイテレータがほしくなる。

総合的なライブラリを拾ってくる手間よりも,自作関数を継ぎ足したほうが楽だったりする。(イテレータ内でのthisの値の仕様とか調べるのが面倒だったりするので) ====

// 配列のイテレータ
Array.prototype.each = function( func ){
	for( var i = 0; i < this.length; i ++ ){
		func.call( this, this[i], i ); 
	}
	return this; // チェインを継続
};


// map
Array.prototype.map = function( func ){
	var _arr = [];
	this.each(function( item, ind ){
		_arr.push( func.call( _arr, item, ind ) );
	});
	return _arr;
};


// オブジェクトを配列に変換
Array.src = function( iterable, func_item, func_length ){
	var arr = [];
	
	var length = null;
	if( func_length ){
		length = func_length( iterable );
	}else{
		iterable.length;
	}
	
	for( var i = 0; i < length; i ++ ){
		if( func_item ){
			arr.push( func_item( iterable, i ) );
		}else{
			arr.push( iterable[ i ] );
		}
	}
	return arr;
};


// Rubyのinjectに相当するメソッド
// http://d.hatena.ne.jp/TipsMemo+computer-technology/20150110/p1
Array.prototype.reduce = function( func, init_value ){
	// 初期値をセット
	var result = init_value;
	
	// 各要素ごとに
	this.each(function( item ){
		// 結果を累積更新する
		result = func( result, item )
	});
	
	// 累積結果を返す
	return result;
};


// 多次元配列を1次元にならす関数。
// 内部でreduceを使用
Array.prototype.flatten = function(){
	return this.reduce(
		function( result, item ){
	    	return (
	    		//Array.isArray( item ) // WSHや古いIEでは動かない
	    		( item instanceof Array )
	    			// 対象要素が配列ならば,再帰する
	    			? result.concat( item.flatten() ) 

	    			// 対象要素が配列でなければ,要素として採用
	    			: result.concat( item )
	    	);
		},
		
		// 空配列からはじめる
		[]
	);
};


このコードのポイント:

  • eachでもメソッドチェインが継続する。他ライブラリだと,そこでチェインがとぎれることも多い。
  • イテレータ内でthisが要素を指すと,トラブルの元になる。なのでそれは避けている。

JavaScriptの動かないコード(中級編)callで,コンテキスト引数にnull・undefinedや,falseなどプリミティブ型の値を渡した時のthisの挙動
http://d.hatena.ne.jp/language_and_engineering/20141226/JavaScriptCallMethodArg

  • 配列のイテレータとして,eachを自前で実装したとする。 そしてeach内の無名関数では,thisが配列の各要素を表すとする。 この実装はまずい。 配列の要素としてnullとかundefinedを許可できなくなってしまうからだ。
  • srcで,配列に変換できるというのもいいメソッドだ。getElementsByTagNameで取得した要素リストなんかは,lengthを持っているものの,Arrayではない。なのでeach()やmap()が使えなくてめんどい,という事態がよくある。ここで,prototype.jsでの$Aに相当する関数を使って,NodeListをArrayに変換しておけば,あとあとの実装が楽。

いまからはじめるPrototype.js (1) Prototype.jsの概要と$で始まるメソッド | マイナビニュース
http://news.mynavi.jp/series/prototypejs/001/

  • $A()はコレクションオブジェクトを配列として取得する。コレクションオブジェクトとは、複数の要素を持つオブジェクトのことをいう。たとえば関数の引数群を表すargumentsやdocument.getElementsByTagName()の戻り値などがそれにあたる。
  • コレクションオブジェクトを配列にしておくと、JavaScriptPrototype.jsで用意されている配列のための便利なメソッドが利用できる。


今後の課題:

  • 関数をもっと充実させたい。最近のモダンなライブラリや,Haskellのfoldrなどをよく調べ,関数プログラミングのスタイルでコーディングできるように洗練させて,配列の便利関数のライブラリとして独立させたい。WSH/JScript(できればVBScriptも)や,ブラウザ上のJavaScriptに付加できる形にしたい。
  • 二次元配列をスキャンするAPIを整備したい,という要望が以前にあった。動的計画法アルゴリズムを実装するときなどに,二次元配列にはよくお世話になる。なので,一次元の枠を越えて扱えるようになるともっとよい。

JavaScriptで,文字列のdiff差分を計算するコード。アルゴリズム動的計画法 - ソフトウェア勉強ログとサンプルコード
http://source-code-student.hatenablog.jp/entry/20141226/p1


迷路をウネウネと生成する,ライフゲーム的なJavaScriptアスキーアートで反復描画アニメーション)
http://d.hatena.ne.jp/language_and_engineering/20140624/CreateMeiroJavaScript