DTPab

DTPにまつわるあれこれ

ES3で使うためのArray.filter

【追記 5/30 13:06】
コードに不具合があったため修正しました。あるふぁ(仮)さん、いつもありがとうございます(記事末尾にも追記あり)。

【追記 5/30 15:30】
コードに不具合があったため修正しました。またまたあるふぁ(仮)さん、そして(-z)さん、ありがとうございます(コードをgistにアップしました)。

はじめに

先日、Array.filterをECMAScript3準拠のExtendScriptでも使いたいと思い、MDNのサイトからPolyfillを参照しました。

developer.mozilla.org

ところが、実際に動かしてみるとwhile文が無限ループする。
そもそもコードがほかのMDNのPolyfillと比べてとても汚い。汚いというか{}が使われてないから非常に違和感がある。if文でthisArgを調べて分岐させて似たようなwhile文を2つ書くというのも筋が悪い。なんだこのコードは。

というわけで書き直しました。ExtendScriptでもArray.filterを使いたいという方は、末尾のコードをどうぞ。

ECMAScript 5.1を参照

まずは公式ドキュメント(英文)を参照しました。

ECMAScript Language Specification - ECMA-262 Edition 5.1

原文と合わせて、@MD5500さんからお借りしているこちらを参照しました(多謝!)。

f:id:uske_S:20180530085920j:plain

Array.filterメソッド

コードはgistにアップしました。

gist.github.com

ちょっと冗長なコードですが、ECMAScriptに沿って定義したつもりです。間違いがあればご指摘いただけると助かります。

ExtendScriptでの使い方

Arrayオブジェクトをプロトタイプ拡張するものです。一度定義したエンジン内*1では、どこでもArray.filterメソッドが使えるようになります。
上のコードをそのままスクリプトの冒頭に記述してもいいですが、こういうものは#includeしましょう。

まずはコードを適当な名前で「array_filter.jsxinc」などとして保存します。#includeが前提のスクリプトは、拡張子をjsxincとします*2

続いて、読み込みたいスクリプトの冒頭で#include array_filter.jsxincとします。これはスクリプトとこのjsxincファイルが同じフォルダ階層にある場合です。でなければ#includeのあとに絶対パスを記述するか、もしくは#includepathで読み込み先のパスを定義して#include array_filter.jsxincとします*3#includepathは複数の参照先パスを定義できるので、覚えておくとExtendScriptでもライブラリ(のような感じで使うjsxincファイル)を扱いやすくなります。

コードの例

#include array_filter.jsxinc
var a = [13,6,20,1].filter(function (ele, index, array){
    return ele > 10;
});
$.writeln(e); //13, 20

あくまで例なのでリテラルで定義した配列[13,6,20,1]に直接filterメソッドを呼びましたが、配列を変数に代入し、その変数に対して呼ぶ形でももちろん大丈夫です。
Array.filterメソッドには3つの引数を持つコールバック関数を渡します(第二引数、第三引数は省略可能)。
コールバック関数の第一引数は配列から順に抽出した値です。
第二引数はそのindex(順番)、第三引数は配列それ自体です。
また、省略可能ですが、コールバック関数にthisとして渡したいオブジェクトも(Array.filterメソッドの第二引数として)渡すことができます。このあたりはクロージャなどの入れ子の関数がたくさん存在するケースで威力を発揮しますが、ExtendScriptのちょっとしたスクリプトではまず使うことはないでしょうね。なので説明は割愛します。
コールバック関数は直接引数に記述しましたが、これも事前に定義しておいたものを変数として渡したり、といった形でも大丈夫です。

【追記 5/30 13:06】更新履歴

コールバック関数にreturn trueだけ、要するに全部trueで返す場合、元の配列と同じ配列ができるようにしました。
以前のコードでは、配列の値がTruthyのものだけ抽出していましたが、これは本来のArray.filterメソッドと異なる挙動だったため修正しました。
それとあわせて、コールバック関数に何も記述しない場合に余計なプロパティまで取得していたのを修正しました。
--追記ここまで--

以上、ES3(ExtendScript)でArray.filterメソッドを使うコードでした。

*1:ExtendScriptでは、targetengineを定義するとそのエンジン内でprototype拡張することができます。「ESTKのtargetengineの挙動」を参照。

*2:AdobeJavaScript Tool Guide CC(英文)」より、Chapter 8: ExtendScript Tools and Features, p234を参照。もしくはこちら

*3:前掲注参照。