配列を作らない$X関数 (失敗)
XPathのevaluate結果に対する処理をスマートに書くための便利関数 - 今日もスミマセン。を見て、思いついた。
$X関数は便利だけど、配列を詰めなおす処理が今ひとつだと感じてました。
で、その改案です。
function $XA (exp, context) { context || (context = document); var expr = (context.ownerDocument || context).createExpression(exp, function (prefix) { return document.createNSResolver(context.documentElement || context).lookupNamespaceURI(prefix) || context.namespaceURI || document.documentElement.namespaceURI || ""; }); var result = expr.evaluate(context, XPathResult.ANY_TYPE, null); switch (result.resultType) { case XPathResult.STRING_TYPE : return result.stringValue; case XPathResult.NUMBER_TYPE : return result.numberValue; case XPathResult.BOOLEAN_TYPE: return result.booleanValue; case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: return { each:function(func, thisObject){ var n = null; while (n = result.iterateNext()) func.call(thisObject,n); }, forEach:function(func, thisObject){ var n = null, i = 0; while (n = result.iterateNext()) func.call(thisObject,n,i++); }, map:function(func, thisObject){ var n = null, i = 0, res = []; while (n = result.iterateNext()) res.push(func.call(thisObject,n,i++)); return res; }, filter:function(func, thisObject){ var n = null, i = 0, res = []; while (n = result.iterateNext()) if (func.call(thisObject, n, i++)) res.push(i); return res; } }; } return null; }
$XAは、each、forEachなどのメソッドをもったObjectを返すので、$XA.each(function)と書ける。これでループ処理は1回で済む。実際に高速化するかはともかく気持ち的にすっきりした*1。別の問題があった。id:javascripter さんのコメント 参照。
someとかeveryとかArrayの機能は一通り詰め込むという手もあるけど、必要なときに実装すれば十分かな。そういう意味で、Objectではなく、上記のeach相当の関数を返すのもありかも。 $XA('//a')(function(n){}) って感じで使う。
function $XA (exp, context) { context || (context = document); var expr = (context.ownerDocument || context).createExpression(exp, function (prefix) { return document.createNSResolver(context.documentElement || context).lookupNamespaceURI(prefix) || context.namespaceURI || document.documentElement.namespaceURI || ""; }); var result = expr.evaluate(context, XPathResult.ANY_TYPE, null); switch (result.resultType) { case XPathResult.STRING_TYPE : return result.stringValue; case XPathResult.NUMBER_TYPE : return result.numberValue; case XPathResult.BOOLEAN_TYPE: return result.booleanValue; case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: return function (func, thisObject) { var n = null; while (n = result.iterateNext()) func.call(thisObject,n); }; } return null; }
*1:パフォーマンスはそのうちチェックする。関数呼び出しは増えてる?ので、遅いかもしれない。。