読者です 読者をやめる 読者になる 読者になる

配列を作らない$X関数 (失敗)

javascript XPath

XPathのevaluate結果に対する処理をスマートに書くための便利関数 - 今日もスミマセン。を見て、思いついた。

$X関数は便利だけど、配列を詰めなおす処理が今ひとつだと感じてました。
で、その改案です。

http://gist.github.com/19461

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){}) って感じで使う。

http://gist.github.com/19468

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:パフォーマンスはそのうちチェックする。関数呼び出しは増えてる?ので、遅いかもしれない。。