DTPab

DTPにまつわるあれこれ

配列に要素が含まれるかどうかを調べるArray.some()メソッドをポリフィルする

あらまし

haragurai-is-bad氏が、記事中でArray.indexOf()メソッドをポリフィルしてExtendScriptに実装していらした。

haraguai-is-bad.hatenablog.com

実はポリフィルしてた

記事のコメントにも書いたとおり、僕はArray.some()メソッドをポリフィルしています。

使用例

使い方としてはこんな感じ。
選択したオブジェクトが何者かによって処理を変えるサンプルです。

//@include "array_some_jsxinc"  // 適宜インクルードする

var doc = app.activeDocument;
var sel = doc.selection[0];
var acceptClasses = [Text, Word, Character, Line, Paragraph]; // 選択を許可するインスタンス

if (acceptClasses.some(function (elem) { return (sel instanceof elem); })) {
    $.writeln("許可されたインスタンスです");
} else {
    $.writeln("このオブジェクトのインスタンスは "+sel.constructor.name+" です");
}

Array.some()メソッドの基本

基本はMDNを参照
ここにあるようにArray.some()メソッド自体の引数は最大で2つ(コールバック関数とthisオブジェクト)、コールバック関数の引数が最大で3つです。
ES3の仕様でコールバック関数を書くのがめちゃくちゃダサいし冗長なのですが*1、それは仕方ないので諦めます。泥臭くfunction文書いてください。

MDNを参照していただくともうそれ以上の情報はないんですが一応紹介しておくと、コールバック関数の第一引数に配列の各要素が取り出されます。その各要素に対して、コールバック関数が適用されるようなイメージです。
先のサンプルコードでいうと、

function (elem) { return (sel instanceof elem); }

コールバック関数はこの部分。配列acceptClassesの各要素が変数elemに引っ張り出されて、このコールバック関数を実行します。配列の最初の要素はTextなので、sel instanceof Text が評価されます。これがfalseであれば次の要素(Word)が…という具合です。
その間に一度でもtrueが帰ってくればArray.some()メソッド自体がtrueを返す、というわけですね。

応用してみる?

/**
 * 選択したオブジェクト群に1つでも特定のテキストが含まれるかどうか
 */
//@include "array_some_jsxinc"

var doc = app.activeDocument;
var sel = doc.selection;
var re = /^\d+/; // 先頭が数字で始まる

if (sel.some(function (elem) {
    return elem.hasOwnProperty("contents") && re.test(elem.contents);
})) {
    $.writeln("正規表現 " + re.source + " がマッチするテキストがあります");
} else {
    $.writeln("マッチしません");
}

こんな感じで、配列の中の特定のプロパティを参照することもできます。使い方によっては非常に便利なのでお試しあれ〜

*1:MDNに掲載されているアロー関数のシンプルさったらない。泣ける