並んでいるデータを処理する時は,必ずイテレータがほしくなる。
総合的なライブラリを拾ってくる手間よりも,自作関数を継ぎ足したほうが楽だったりする。(イテレータ内での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()の戻り値などがそれにあたる。
- コレクションオブジェクトを配列にしておくと、JavaScriptやPrototype.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