M.Hiroi's Home Page

JavaScript Programming

お気楽 Underscore.js 超入門


Copyright (C) 2016-2025 Makoto Hiroi
All rights reserved.

Collections

Collections に分類されている関数は配列またはオブジェクトを操作します。マッピング (map)、フィルター (filter)、畳み込み (reduce) といった高階関数も用意されています。これらの高階関数については拙作のページ お気楽 JavaScript プログラミング超入門 高階関数 で説明しています。よろしければ参考にしてください。

●マッピング

_.map(array_or_object, func, [context]) => new_array  // 別名 collect
_.pluck(array_or_object, propertyName) => new_array

map は array_or_object の要素 (またはプロパティ) に func を適用して、その結果を格納した新しい配列を返します。配列の場合、func の引数には (要素, 添字, 配列) が渡されます。オブジェクトの場合は (値, キー, オブジェクト) が渡されます。context にオブジェクトを指定すると、func の中では this を使ってオブジェクトを参照することができます。

> _.map([1,2,3,4,5], n => n * n)
[ 1, 4, 9, 16, 25 ]
> _.map({foo: 10, bar: 20}, n => n * n)
[ 100, 400 ]
> var x = _.map({foo: 10, bar: 20}, (n, k) => [n * n, k])
undefined
> x[0]
[ 100, "foo" ]
> x[1]
[ 400, "bar" ]

pluck は array_of_object に格納されているオブジェクトのプロパティの値を取り出し、それを新しい配列に格納して返します。基本的な動作は次のプログラムと同じです。

リスト : pluck の基本的な動作

function my_pluck(ary, name) {
    return _.map(ary, obj => obj[name]);
}
> function my_pluck(ary, name) {
...   return _.map(ary, obj => obj[name]);
... }
undefined
> my_pluck([{foo: 1, bar: 2}, {foo: 10, bar: 20}], 'foo')
[ 1, 10 ]
> my_pluck([{foo: 1, bar: 2}, {foo: 10, bar: 20}], 'bar')
[ 2, 20 ]

●フィルター

_.filter(array_or_object, func, [context]) => new_array
_.reject(array_or_object, func, [context]) => new_array
_.where(array_or_object, object) => new_array

filter は関数 func が真を返す要素 (プロパティ) を新しい配列に格納して返します。reject は filter の逆で、func が偽を返す要素 (プロパティ) を新しい配列に格納してを返します。関数 func に渡される引数は map と同じです。

> _.filter([1,2,3,4,5], n => n % 2 == 0)
[ 2, 4 ]
> _.filter({foo: 1, bar: 2}, n => n % 2 == 0)
[ 2 ]
> _.reject([1,2,3,4,5], n => n % 2 == 0)
[ 1, 3, 5 ]
> _.reject({foo: 1, bar: 2}, n => n % 2 == 0)
[ 1 ]

where は object で指定したプロパティと値に一致するオブジェクトを新しい配列に格納して返します。

> var x = _.where([{foo: 1, bar: 10}, {foo: 2, bar: 20}, {foo: 1, bar: 30}], {foo: 1})
undefined
> x[0]
{ foo: 1, bar: 10 }
> x[1]
{ foo: 1, bar: 30 }

●畳み込み

_.reduce(array_or_object, func, init, [context]) => value      // 別名 foldl, inject 
_.reduceRight(array_or_object, func, init, [context]) => value // 別名 foldr

reduce は array_or_object の先頭 (左側) から、reduceRight は末尾 (右側) から要素を畳み込みます。関数 func の引数には (累積値, 要素, 添字、配列) または (累積値, 値, キー, オブジェクト) が渡されます。

> _.reduce([1,2,3,4,5], (a, n) => a + n, "")
"12345"
> _.reduceRight([1,2,3,4,5], (a, n) => a + n, "")
"54321"
> _.reduce({foo: 1, bar: 2, baz: 3}, (a, n) => a + n, "")
"123"
> _.reduceRight({foo: 1, bar: 2, baz: 3}, (a, n) => a + n, "")
"321"

●巡回

_.each(array_or_object, func, [context])

each は配列の要素またはオブジェクトのプロパティに関数 func を適用します。返り値は array_or_object です。

> _.each([1,2,3,4,5], n => console.log(n))
1
2
3
4
5
[ 1, 2, 3, 4, 5 ]
> _.each({foo: 10, bar: 20}, n => console.log(n))
10
20
{ foo: 10, bar: 20 }

●検索

_.find(array_or_object, func, [context]) => value
_.contains(array_or_object, value) => boolean

find は array_or_object を線形探索し、関数 func が真を返す最初の要素 (またはプロパティの値) を返します。見つからない場合は undefined を返します。contains は array_or_object に value が含まれていれば true を、そうでなければ false を返します。

> _.find([1,2,3,4,5], n => n % 3 == 0)
3
> _.find([1,2,3,4,5], n => n % 6 == 0)
undefined
> _.find({foo: 1, bar: 3, baz: 5}, n => n % 3 == 0)
3
> _.find({foo: 1, bar: 3, baz: 5}, n => n % 6 == 0)
undefined

> _.contains([1,3,5,7], 5);
true
> _.contains([1,3,5,7], 2);
false
> _.contains({foo: 1, bar: 3, baz: 5}, 3)
true
> _.contains({foo: 1, bar: 3, baz: 5}, 6)
false
_.every(array_or_object, func, [context]) => boolean    // 別名 all
_.some(array_or_object, [func], [context]) => boolean   // 別名 any

every は array_or_object の要素に関数 func を適用し、結果がすべて真ならば true を返します。some は array_or_object の要素に関数 func を適用し、true を返す要素がひとつでもあれば true を返します。結果がすべて false ならば false を返します。func を省略した場合は要素の値で真偽を判定します。

> _.every([2,4,6,8], n => n % 2 == 0)
true
> _.every([2,4,6,8,9], n => n % 2 == 0)
false
> _.some([2,4,6,8,9], n => n % 2 != 0)
true
> _.some([2,4,6,8], n => n % 2 != 0)
false
> _.some([0,0,0,0], n => n % 2 != 0)
false
> _.some([0,0,0,0])
false
> _.some([0,0,1,0])
true

●グルーピング

_.groupBy(array_or_object, func) => new_object
_.countBy(array_or_object, func) => new_object

groupBy は array_or_object の要素に関数 func を適用し、その結果でグループ分けします。func の結果が new_object のキーになり、値は要素を格納した配列になります。なお、func にはプロパティ名を指定することもできます。その場合はプロパティの値でグループ分けされます。countBy はグループ分けしたあとの要素数をカウントします。

> var x = _.groupBy([1,2,3,4,5,6,7,8,9], n => n % 4)
undefined
> x[0]
[ 4, 8 ]
> x[1]
[ 1, 5, 9 ]
> x[2]
[ 2, 6 ]
> x[3]
[ 3, 7 ]
> var y = _.countBy([1,2,3,4,5,6,7,8,9], n => n % 4)
undefined
> y[0]
2
> y[1]
3
> y[2]
2
> y[3]
2

●ソート, シャッフル

_.sortBy(array_or_object, [func], [context]) => new_array
_.shuffle(array_or_object) => new_array

sortBy は array_or_object を昇順にソートした新しい配列を返します。func を指定すると、要素を func に適用し、その返り値を基準にソートします。func には関数のかわりにプロパティを指定することができます。shuffle は array_or_object の要素をシャッフルした新しい配列を返します。

> _.sortBy([5,6,7,4,3,2,9,1])
[
  1, 2, 3, 4, 
  5, 6, 7, 9
]
> _.sortBy([5,6,7,4,3,2,9,1], n => -n)
[
  9, 7, 6, 5,
  4, 3, 2, 1
]
> _.sortBy({foo: 2, bar: 1, baz: 3})
[ 1, 2, 3 ]
> _.sortBy(["foo", "a", "oops"], 'length')
[ 'a', 'foo', 'oops' ]
> _.shuffle([1,2,3,4,5])
[4, 1, 3, 5, 2]
> _.shuffle([1,2,3,4,5])
[3, 4, 5, 2, 1]
> _.shuffle([1,2,3,4,5])
[3, 2, 4, 5, 1]

●その他

_.min(array_or_object, [func], [context]) => value
_.max(array_or_object, [func], [context]) => value

min は array_or_object の中から最小値を選んで返します。max は最大値を選んで返します。func を指定した場合は、要素に func を適用して、その返り値を基準に最小値 (または最大値) を選択します。

> _.max([5,6,4,7,3,8,2,9,1])
9
> _.max([5,6,4,7,3,8,2,9,1], n => -n)
1
> _.min([5,6,4,7,3,8,2,9,1])
1
> _.min([5,6,4,7,3,8,2,9,1], n => -n)
9
_.toArray(object) => new_array
_.size(array_or_object) => number

toArray は object を配列に変換します。size は array_or_object の要素数を返します。

> _.toArray({foo: 1, bar: 2, baz: 3})
[ 1, 2, 3 ]
> _.size({foo: 1, bar: 2, baz: 3})
3

Arrays

Arrays には配列を操作する関数が定義されています。

●配列の分解

_.first(array, [n]) => value / new_array  // 別名 head, take
_.rest(array, [n]) => new_array           // 別名 tail, drop

first は配列の先頭要素を返します。n を指定すると、先頭から n 個の要素を配列に格納して返します。rest は先頭の要素を取り除いた新しい配列を返します。n を指定すると先頭から n 個の要素を取り除いた配列を返します。Lisp / Scheme の関数 car, cdr と似ていますが、rest は新しい配列を返すことに注意してください。

> _.first([1,2,3,4,5])
1
> _.first([1,2,3,4,5], 3)
[ 1, 2, 3 ]
> _.rest([1,2,3,4,5])
[ 2, 3, 4, 5 ]
> _.rest([1,2,3,4,5], 3)
[ 4, 5 ]
_.initial(array, [n]) => new_array
_.last(array, [n]) => value / new_array

initial は配列の最後の要素を取り除いた新しい配列を返します。n を指定すると、最後から n 個の要素を取り除いた新しい配列を返します。last は配列の最後の要素を返します。n を指定すると、最後から n 個の要素を新しい配列に格納して返します。

> _.initial([1,2,3,4,5])
[ 1, 2, 3, 4 ]
> _.initial([1,2,3,4,5], 3)
[ 1, 2 ]
> _.last([1,2,3,4,5])
5
> _.last([1,2,3,4,5], 3)
[3, 4, 5]

●配列の生成

_.range([start], end, [step]) => new_array

range は start から end - 1 までの整数を配列に格納して返します。引数が一つで start が省略された場合、リストの要素は 0 から始まり、値を +1 しながら end - 1 までの数値を生成します。引数が 2 つの場合は start から end - 1 までの数値を生成します。引数が 3 つの場合は、start から end 未満までの数値を step 分加算しながら生成します。

> _.range(10)
[
  0, 1, 2, 3, 4,
  5, 6, 7, 8, 9
]
> _.range(1, 10)
[
  1, 2, 3, 4, 5,
  6, 7, 8, 9
]
> _.range(1, 10, 2)
[ 1, 3, 5, 7, 9 ]
_.zip(array, ...) => new_array

zip は複数の配列を受け取り、同じ位置にある要素を一つの配列にまとめ、それを新しい配列に格納して返します。たとえば、配列 A, B, ..., Z を zip に渡すと、i 番目の要素は [Ai, Bi, ..., Zi] になります。

> var x = _.zip(["foo", "bar", "baz"], [1, 2, 3])
undefined
> x[0]
[ 'foo', 1 ]
> x[1]
[ 'bar', 2 ]
> x[2]
[ 'baz', 3 ]
> x
[ [ 'foo', 1 ], [ 'bar', 2 ], [ 'baz', 3 ] ]

●探索

_.indexOf(array, value, [isSorted])
_.lastIndexOf(array, value, [start])

indexOf は value と等しい要素を探索します。見つけた場合は位置 (添字) を返します。見つからない場合は -1 を返します。isSorted に true を指定すると配列を二分探索します。このとき、配列は昇順にソートしておく必要があります。lastIndexOf は配列の末尾から探索します。start は探索の開始位置を指定します。

> _.indexOf([1,2,3,4,5], 3);
2
> _.indexOf([1,2,3,4,5], 10);
-1
> _.lastIndexOf([1,2,1,2,3,1,2,3,4], 1)
5
> _.lastIndexOf([1,2,1,2,3,1,2,3,4], 5)
-1

●集合演算

次に示す関数は配列を集合とみなして集合演算を行います。

_.union(array, ...) => new_array
_.intersection(array, ...) => new_array
_.difference(array, ...) => new_array
_.uniq(array, [isSorted], [func]) => new_aray

union は和集合を求めます。intersection は積集合を求めます。difference は差集合を求めます。uniq は重複要素を削除した新しい配列を返します。配列をソートしておいて、isSorted を true に指定すると、高速に実行することができます。関数 func を指定すると要素に func を適用して、その返り値で等値を判定します。

> _.union([1,2,3,4], [3,4,5,6])
[1, 2, 3, 4, 5, 6]
> _.intersection([1,2,3,4], [3,4,5,6])
[3, 4]
> _.difference([1,2,3,4], [3,4,5,6])
[1, 2]
> _.uniq([1,2,1,2,3,1,2,3,4])
[1, 2, 3, 4]

●平坦化

_.flatten(array、[shallow]) => new_array

flatten は入れ子になった配列を平坦化します。shallow に true を指定すると、トップレベルの階層だけ平坦化します。

> _.flatten([1,[2,[3,4],5],6])
[1, 2, 3, 4, 5, 6]
> _.flatten([1,[2,[3,4],5],6], true)
[1, 2, [3, 4], 5, 6]

●その他

_.compact(array) => new_array
_.without(array, value, ...) => new_array

compact は偽と判定される要素を取り除いた新しい配列を返します。without は value 以降に指定された値を取り除いた新しい配列を返します。

> _.compact([1, 2, 3, 0, "", undefined, 4])
[1, 2, 3, 4]
> _.without([1, 2, 3, 4, 5], 1, 3, 5)
[2, 4]
_.object(array, [values]) => new_object

object は配列をオブジェクトに変換します。引数が一つの場合、配列の要素を [キー, 値] にしてください。引数が 2 つある場合は、第 1 引数にキーを、第 2 引数に値を格納した配列を渡します。

> _.object([["foo", 1], ["bar", 2]])
{ foo: 1, bar: 2 }
> _.object(["foo", "bar", "baz"], [1,2,3])
{ foo: 1, bar: 2, baz: 3 }

Objects

Objects にはオブジェクトを操作する便利な関数 (メソッド) が定義されています。

●キーと値

_.keys(object) => new_array
_.values(object) => new_array
_.pairs(object) => new_array
_.invert(object) => new_object
_.has(object, key) => boolean

keys は object 内のキー (プロパティ名) を配列に格納して返します。values は object 内のキーの値を配列に格納して返します。pairs は object 内のキーと値を組 [key, value] にして、それを配列に格納して返します。invert はキーと値を反転した新しいオブジェクトを返します。has は object のキーに key が存在すれば true を返します。

> var obj = {foo: 1, bar: 2, baz: 3, oops: 4}
undefined
> _.keys(obj)
[ 'foo', 'bar', 'baz', 'oops' ]
> _.values(obj)
[ 1, 2, 3, 4 ]
> _.pairs(obj)
[ [ 'foo', 1 ], [ 'bar', 2 ], [ 'baz', 3 ], [ 'oops', 4 ] ]
> _.invert(obj)
{ '1': 'foo', '2': 'bar', '3': 'baz', '4': 'oops' }
> _.has(obj, 'foo')
true
> _.has(obj, 'Foo')
false

●オブジェクトのコピー

_.clone(object) => new_object

clone は object のクローンを生成して返します。ただし、キーの値が配列やオブジェクトの場合、配列やオブジェクトがコピーされることはありません。

> var a = [1,2,3,4,5]
undefined
> var b = {foo: a, bar: 1}
undefined
> var c = _.clone(b)
undefined
> c
{ foo: [ 1, 2, 3, 4, 5 ], bar: 1 }
> a[0] = 10
10
> a[0]
10
> b.foo[0]
10
> c.foo[0]
10
_.pick(object, key, ...) => new_object
_.omit(object, key, ...) => new_object

pick は object から key 以降に指定したプロパティをコピーして返します。omit は逆に object から key 以降のプロパティ以外のプロパティをコピーして返します。

> _.pick({foo: 1, bar: 2, baz: 3}, 'foo', 'baz')
{ foo: 1, baz: 3 }
> _.omit({foo: 1, bar: 2, baz: 3}, 'foo', 'baz')
{ bar: 2 }
_.extend(object, source, ...) => object
_.defaults(object, default, ...) => object

extend は source 以降のオブジェクトの全プロパティを object にコピーして返します。object と source 以降のオブジェクトに同じプロパティが存在する場合、その値は書き換えられます。defaults は defulat 以降のオブジェクトのプロパティで、object に存在しないプロパティ (object で undefined のもの) を object にコピーして返します。

> _.extend({foo: 1, bar: 2}, {foo: 10, baz: 20})
{ foo: 10, bar: 2, baz: 20 }
> _.defaults({foo: 1, bar: 2}, {foo: 10, baz: 20})
{ foo: 1, bar: 2, baz: 20 }

●等値の判定

_.isEqual(object, other) => boolean

isEqual は引数の object と other が等しいか判定します。数値と文字列の場合は演算子 === で判定します。配列の場合は、大きさが等しくて、すべての要素が isEqual で真を返すとき「真」と判定します。オブジェクトの場合、すべてのキーが等しくて、その値が isEqual で真を返すとき「真」と判定します。

> _.isEqual(1, 1)
true
> _.isEqual(1, "1")
false
> _.isEqual("1", "1")
true
> _.isEqual([1], [1])
true
> _.isEqual([1], [1, 2])
false
> _.isEqual([1,3], [1, 2])
false
> _.isEqual([1], ["1"])
false
> var a = {foo: 1, bar: 2}
undefined
> var b = {foo: 1, bar: 2}
undefined
> a == b
false
> _.isEqual(a, b)
true
> _.isEqual(a, {foo: 1})
false
> _.isEqual(a, {foo: 1, bar: 3})
false

●データ型の判定

データ型を判定する関数のことを関数型言語では「型述語」と呼ぶことがあります。Objects には is で始まる型述語が多数用意されています。どの関数も返り値は boolean (true, false) になります。

表 : データ型を判定する関数
関数名機能
_.isEmpty(object)空のオブジェクトか
_.isArrray(object)配列か
_.isObject(object)オブジェクトか
_.isFunction(object)関数か
_.isString(object)文字列か
_.isNumber(object)数値 (NaN を含む) か
_.isNaN(object)NaN か
_.isFinite(object)有限数か
_.isBoolean(object)boolean (true, false) か
_.isNull(object)null か
_.isUndefined(object)undefined か
_.isDate(object)日付オブジェクトか
_.isRegExp(object)正規表現オブジェクトか
_.isArguments(object)Arguments オブジェクトか

Functions

Functions には関数を操作するための便利な関数が用意されています。

_.partial(func, *args) => new_func

partial は引数の関数 func を「部分適用」した新しい関数 new_func を返します。関数の部分適用とは、指定した引数に値を設定して、残りの引数を受け取る関数を生成することです。

> var add = (a, b) => a + b
undefined
> add(1, 2)
3
> var add10 = _.partial(add, 10)
undefined
> add10(20)
30
> var add100 = _.partial(add, 100)
undefined
> add100(10)
110
_.bind(func, object, [*args]) => new_func

bind は引数の関数 func にオブジェクト object を束縛 (bind) した新しい関数 new_func を返します。new_func 内の変数 this は束縛した object になります。引数 args が指定された場合、partial と同様に関数の部分適用が行われます。

> function hello() { return "hello " + this.name; }
undefined
> hello()
'hello undefined'
> var ken = _.bind(hello, {name: "Ken"})
undefined
> ken()
'hello Ken'
> var bob = _.bind(hello, {name: "Bob"})
undefined
> bob()
'hello Bob'
_.memoize(func, [hashFunc]) => new_func

memoize は引数の関数 func をメモ化した関数 new_func を返します。関数の「メモ化 (memoize)」とは、計算した値を表 (ハッシュ表) に格納しておいて、2 回目以降は表から計算結果を求めることで、処理を高速化する手法のことです。詳しい説明は拙作のページ お気楽 JavaScript プログラミング超入門 クロージャ をお読みください。

> function fibo(n) { return n < 2 ? n : fibo(n - 2) + fibo(n - 1); }
undefined
> fibo = _.memoize(fibo)
[Function: memoize] { cache: {} }
> fibo(10)
55
> fibo(40)
102334155
> fibo(45)
1134903170
_.compose(*func) => new_func

compose は引数に与えられた複数の関数を合成した新しい関数 new_func を返します。たとえば、_.compose(f, g, h) とすると、合成した関数は f(g(h())) になります。

> function foo() { console.log("foo"); }
undefined
> function bar() { console.log("bar"); }
undefined
> function baz() { console.log("baz"); }
undefined
> var test = _.compose(foo, bar, baz)
undefined
> test()
baz
bar
foo
undefined

> function foo1(x) { return 2 * x + 1; }
undefined
> function bar1(y) { return y * y + 3 * y; }
undefined
> var baz1 = _.compose(bar1, foo1)
undefined
> baz1(4)
108

Utility

今まで説明した関数以外にも、便利な関数が Utility に用意されています。

_.identity(value) => value

identity は引数 value をそのまま返します。このような関数を「恒等関数 (identity function)」といいます。

> _.identity(1)
1
> _.identity('hello')
'hello'
> _.identity([1,2,3,4,5])
[ 1, 2, 3, 4, 5 ]
_.times(n, iteratee, [context]) => array

times は引数の関数 iteratee を n 回呼び出します。iteratee の引数には 0 から n - 1 までの整数値が渡されます。返り値は iteratee の結果を格納した配列です。

> _.times(5, n => console.log(n))
0
1
2
3
4
[undefined, undefined, undefined, undefined, undefined]
> _.times(5, (n, x) => n)
[ 0, 1, 2, 3, 4 ]
_.random(min, max) => integer

random は min 以上 max 以下の乱数 (整数値) を生成します。引数が一つの場合は 0 以上引数以下の乱数を生成します。

> _.random(0, 5)
5
> _.random(0, 5)
0
> _.random(0, 5)
1
> _.random(0, 5)
3
> _.random(5)
5
> _.random(5)
1
> _.random(5)
4
> _.random(5)
0
_.escape(string) => string
_.unescape(string) => string

escape は引数 string の中の文字 & < > ' " を &amp; &lt; &gt; &#x27; &quot; に変換します。unescape は escape の逆変換を行います。

> _.escape("&<>'`")
'&amp;&lt;&gt;&#x27;&#x60;'
> _.escape('&<>`"')
'&amp;&lt;&gt;&#x60;&quot;'
> _.unescape("&amp;&lt;&gt;&#x27;&#x60;")
"&<>'`"
> _.unescape("&amp;&lt;&gt;&#x60;&quot;")
'&<>`"'
_.template(templateString, [data], [settings]) => function

template は引数の templateString をコンパイルして関数を生成します。生成された関数は引数にオブジェクトを受け取り、それをテンプレートにあてはめ、結果を文字列にして返します。templateString の中では、次に示す特別な記号を使うことができます。

> var tmp1 = _.template("<% console.log('hello, world') %>")
undefined
> tmp1()
hello, world
''
> var tmp2 = _.template("hello, <%= name %>")
undefined
> tmp2({name: "M.Hiroi"})
'hello, M.Hiroi'
> var tmp3 = _.template("<%- name %>")
undefined
> tmp3({name: "<M.Hiroi>"})
'&lt;M.Hiroi&gt;'

Chaining

chain と value を使うと、Underscore.js のメソッドをドット ( . ) でつなげて記述することができます。chain はメソッドを連結し、その結果を取り出すのが value です。

リスト : chain と value の使用例

var a =_.chain(_.range(1, 10))
        .filter(function(x) { return x % 2 == 0; })
        .map(function(x) { return x * x; })
        .value()
> var a = _.chain(_.range(1,10)).filter(function(x) { return x % 2 == 0; })
.map(function(x) { return x * x; }).value()
undefined
> a
[ 4, 16, 36, 64 ]

chain と value を使わないと、プログラムは次のようになります。

> _.map(_.filter(_.range(1, 10), function(x) { return x % 2 == 0; }),
        function(x) { return x * x; })
[ 4, 16, 36, 64 ]

初版 2016 年 8 月 13 日
改訂 2025 年 3 月 2 日