🙈

【JavaScript】お前はまだコレクション関数を知らない

2021/11/03に公開

はじめに

皆さんはコレクション関数を使いこなしているでしょうか?
コレクション関数をうまく使うことはコーディングのテクニックの1つです。
コレクション関数をうまく使うことで処理の効率が上がったり、コードの可読性が上がり、いわゆるイケてるコードを書くことができます。
今回は自分がよく使用するJavaScriptのコレクション関数をまとめました。

※本記事では、非推奨になっているコレクション関数は記載しません。

この記事の対象は以下です。

  • 公式リファレンスを読むだけじゃ、処理のイメージがつかない人
    • コードと実行結果を載せますので、イメージがつきやすいかと思います。
  • 処理は理解しているが暗記していないため、パッと調べて使いたい人

コードを暗記する必要は全くありません。処理を理解しとけば良いです。メモとして活用ください。

コレクションとは...?

コレクションというのは、データをまとめて格納するデータ構造の総称であり、JavaScriptでは以下のコレクションがあります。

  • 配列
  • 連想配列

構造的には以下のようなものです。

// 配列
const arr = [1, 2, 3];

// 連想配列(他言語では辞書型とも言われます)
const object = {
    "name": "Taro",
    "age": 20,
};

コーディングの際にこれらのコレクションに対して何か操作(追加、削除など)を行いたい場面がよくあると思います。
冒頭でも述べましたが、その操作の引き出しがたくさんあれば効率よく、かつ可読性のあるコードを書くことができます。
そこでコレクション関数をコードと実行結果を添えて、紹介していこうと思います。

配列

まずは配列から紹介します。

concat()

  • 2つ以上の配列を結合させます。
  • 既存の配列を変更せず新しい配列を返す。
const arr1 = ["red", "green", "blue"];
const arr2 = ["white", "black", "gray"];
const arr3 = arr1.concat(arr2);

console.log(arr3);
// [ 'red', 'green', 'blue', 'white', 'black', 'gray' ]

copyWithin()

  • サイズを変更せずに、配列の一部を同じ配列内の別の場所にシャローコピーする。
const arr1 = ["red", "green", "blue", "yellow", "pink"];
const arr2 = arr1.copyWithin(0, 2, 3);
console.log(arr2);
// [ 'blue', 'green', 'blue', 'yellow', 'pink' ]

const arr3 = arr1.copyWithin(1, 3);
console.log(arr3);
// [ 'blue', 'yellow', 'pink', 'yellow', 'pink' ]

entries()

  • 配列内の各要素に対するキー/値のペアを含む新しいArrayイテレーターオブジェクトを返す。
const arr1 = ["red", "green", "blue", "yellow", "pink"];
const arr2 = arr1.entries();
console.log(arr2.next().value);
// [ 0, 'red' ]

console.log(arr2.next().value);
// [ 1, 'green' ]

console.log(arr2.next().value);
// [ 2, 'blue' ]

console.log(arr2.next().value);
// [ 3, 'yellow' ]

console.log(arr2.next().value);
// [ 4, 'pink' ]

every()

  • 配列内の全ての要素が引数に指定された関数で実装された判定に全て満たすかを判定する。
  • booleanを返す。
const isBelowThreshold = (num) => num < 100;

const arr1 = [1, 32, 39, 65, 80, 35];
console.log(arr1.every(isBelowThreshold));
// true

const arr2 = [105, 32, 39, 65, 80, 35];
console.log(arr2.every(isBelowThreshold));
// false

fill()

  • 開始インデックス(デフォルト:0)から終了インデックス(デフォルト:array.length)までのすべての要素を、静的な値に変更した配列を返す。
const arr = [1, 2, 3, 4];
console.log(arr.fill(0, 2, 3));
// [ 1, 2, 0, 4 ]

console.log(arr.fill(5, 1));
// [ 1, 5, 5, 5 ]

console.log(arr.fill(6));
// [ 6, 6, 6, 6 ]

filter()

  • 引数に与えられた条件に一致した要素の配列からなる新しい配列を返す。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const result = arr.filter(color => color.length > 4);
console.log(result);
// [ 'green', 'white', 'black' ]

find()

  • 引数に与えられた条件に一致した最初の要素を返す。
  • 見つからない場合はundefinedを返す。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const result1 = arr.find(color => color.length > 4);
console.log(result1);
// green

const result2 = arr.find(color => color.length > 10);
console.log(result2);
// undefined

findIndex()

  • 引数に与えられた条件に一致した最初の要素の位置を返す。
  • 見つからない場合は-1を返す。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const result1 = arr1.findIndex(color => color.length > 4);
console.log(result1);
// 1

const result2 = arr.findIndex(color => color.length > 10);
console.log(result2);
// -1

flat()

  • 入れ子となっている配列を指定した深さで再起的にフラットした配列を返す。
  • 深さを指定しなかった場合は1が使われます。
const arr = [["red", "green", "blue"], ["white", "black", "gray"]];

const result = arr.flat();
console.log(result);
// [ 'red', 'green', 'blue', 'white', 'black', 'gray' ]

flatMap()

  • 各要素にmap処理を施した後、深さ1のflat()を行う。
  • map() + flat()を行っている。
const arr = [[1, 3, 5], [100, 1000, 1000]];

const result = arr.flatMap(element => element[0] * 2);
console.log(result);
// [ 2, 200 ]

forEach()

  • 引数に与えられた関数を各要素に対して一度ずつ実行suru。
const arr = ["red", "green", "blue", "white", "black", "gray"];
arr.forEach(element, index) =>
    console.log(`${index}: ${element}`)
);
// 0: red
// 1: green
// 2: blue
// 3: white
// 4: black
// 5: gray

from()

  • 配列のようなオブジェクトや反復可能オブジェクトから、新しいArrayインスタンスを生成する。
const arr1 = Array.from('aiueo')
console.log(arr1);
// [ 'a', 'i', 'u', 'e', 'o' ]

const arr2 = Array.from([1, 2, 3], x => x * 2);
console.log(arr2);
[ 2, 4, 6 ]

includes()

  • 特定の要素が配列に含まれているかどうかをbooleanで返す。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const result1 = arr.includes("red");
console.log(result1);
// true

const result2 = arr.includes("gold");
console.log(result2);
// false

indexOf()

  • 引数に与えられた内容と同じ内容を持つ最初の要素の位置を返す。
  • 存在しない場合は-1を返す。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const result1 = arr.indexOf("white");
console.log(result1);
// 3

const result2 = arr.indexOf("gold");
console.log(result2);
// -1

isArray()

  • 渡された値が配列かどうかを判定する。
console.log(Array.isArray([1, 2, 3]));
// true

console.log(Array.isArray({id: 123}));
// false

console.log(Array.isArray('string'));
// false

console.log(Array.isArray(undefined));
// false

join()

  • 全要素を順に連結した文字列を新たに作成して返す。
  • 区切り文字を文字列で引数に指定します。
  • 省略した場合は「,」が区切り文字となる。
  • 要素が一つしかない場合は、区切り文字を使用せずにその要素を返す。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const result1 = arr.join("-");
console.log(result1);
// red-green-blue-white-black-gray

const result2 = arr.join();
console.log(result2);
// red,green,blue,white,black,gray

keys()

  • 配列内の各インデックスのキーからなる、新しいArrayイテレーターオブジェクトを返す。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const iterator = arr.keys();

for (const key of iterator) {
    console.log(key);
}
// 0
// 1
// 2
// 3
// 4
// 5

lastIndexOf()

  • 引数で与えられた要素と同じ内容のものが見つかった最後の位置を返す。
  • 見つからない場合は-1を返す。
const arr = ["red", "green", "blue", "red", "black", "gray"];
const result1 = arr.lastIndexOf("red");
console.log(result1);
// 3

const result2 = arr.lastIndexOf("gold");
console.log(result2);
// -1

map()

  • 配列のすべての要素に対して引数に与えた関数を実行してその結果からなる配列を返す。
const arr = [1, 10, 100, 1000];
const result = arr.map(x => x * 2);
console.log(result);
// [ 2, 20, 200, 2000 ]

of()

  • 引数の数や型にかかわらず、可変長引数から、新しいArrayインスタンスを生成する。
const arr1 = Array.of(7);
console.log(arr1);
// [ 7 ]

const arr2 = Array.of(1, 4, "num");
console.log(arr2);
// [ 1, 4, 'num' ]

pop()

  • 配列から最後の要素を取り除き、その要素を返す。
  • pop()を実行すると元の配列の長さ-1する。
  • 要素がない場合はundefinedを返す。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const result = arr.pop();
console.log(result);
// gray

console.log(arr);
// [ 'red', 'green', 'blue', 'red', 'black' ]

push()

  • 配列の末尾に1つ以上の要素を追加する。
  • 戻り値として新しい配列の要素数を返す。
const arr = ["red", "green"];
const result1 = arr.push("gold");
console.log(result1);
// 3

console.log(arr);
// [ 'red', 'green', 'gold' ]

const result2 = arr.push("silver", "violet");
console.log(result2);
// 5

console.log(arr);
// [ 'red', 'green', 'gold', 'silver', 'violet' ]

reduce()

  • それぞれの要素に対して引数に与えた関数を実行する。
  • 直前の要素における計算結果の返り値を用いて、すべての要素に対して関数を実行した最終結果を返す。
  • 初期値を第2引数に渡すことができます。
const arr = [1, 2, 3, 4];
const reducer = (previousValue, currentValue) => previousValue + currentValue;
console.log(arr.reduce(reducer));
// 10

console.log(arr.reduce(reducer, 5));
// 15

reduceRight()

  • アキュームレーターと配列のそれぞれの値に対して末尾から関数を適用して、単一の値を返す。
const arr = [[0, 1], [2, 3], [4, 5]].reduceRight(
    (accumulator, currentValue) => accumulator.concat(currentValue)
);

console.log(arr);
// [ 4, 5, 2, 3, 0, 1 ]

reverse()

  • 配列の要素を反転する。
const arr = ["red", "green", "blue", "white", "black", "gray"];
arr1.reverse();
console.log(arr);
// [ 'gray', 'black', 'white', 'blue', 'green', 'red' ]

shift()

  • 配列から最初の要素を取り除き、その要素を返す。
  • shift()を実行すると元の配列の長さ-1する。
  • 要素がない場合はundefinedを返す。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const result = arr.shift();
console.log(result);
// red

console.log(arr);
// [ 'green', 'blue', 'white', 'black', 'gray' ]

slice()

  • startとendを指定した場合、startからendまで(※endは含まれない)で選択された配列の一部を新しい配列オブジェクトに作成して返す。
  • 元の配列は変更されない。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const result1 = arr.slice(2);
console.log(result1);
// [ 'blue', 'white', 'black', 'gray' ]

const result2 = arr.slice(2, 4);
console.log(result2);
// [ 'blue', 'white' ]

const result3 = arr.slice(-2);
console.log(result3);
// [ 'black', 'gray' ]

some()

  • 配列内の全ての要素が引数に指定された関数で実装された判定に1要素でも満たすかを判定する。
  • booleanを返す。
const isBeyondThreshold = (num) => num > 100;

const arr1 = [1, 32, 39, 65, 80, 35];
console.log(arr1.some(isBeyondThreshold));
// false

const arr2 = [105, 32, 39, 65, 80, 35];
console.log(arr2.some(isBeyondThreshold));
// true

sort()

  • 配列の要素をソートする。
  • 既定のソート順は昇順で、要素を文字列に変換してから、UTF-16コード単位の値の並びとして比較する。
  • numberは小さい順にならないことに注意。
const arr1 = ['March', 'Jan', 'Feb', 'Dec'];
arr1.sort();
console.log(arr1);
// ["Dec", "Feb", "Jan", "March"]

const arr2 = [1, 30, 4, 21, 100000];
arr2.sort();
console.log(arr2);
// [1, 100000, 21, 30, 4]

splice()

  • 既存の要素を取り除いたり、置き換えたり、新しい要素を追加して、配列の内容を変更する。
  • 第一引数に追加する位置(start)を指定する。
  • 第二引数にstartの位置から取り除く古い要素の個数を指定する。
const arr = ["red", "green", "blue", "white"];
arr1.splice(1, 0, "gold");
console.log(arr);
// [ 'red', 'gold', 'green', 'blue', 'white' ]

arr1.splice(3, 2, "silver");
console.log(arr);
// [ 'red', 'gold', 'green', 'silver' ]

### toLocaleString()

配列の要素を表す文字列を返す。

ロケール固有の文字列に変換されます。

const arr = [1, 'a', new Date('21 Dec 1997 14:12:00 UTC')];
const result = arr.toLocaleString('en', { timeZone: 'UTC' });
console.log(result);
// 1,a,12/21/1997, 2:12:00 PM

toString()

  • 指定された配列とその要素を表す文字列を返す。
const arr = ["red", "green", "blue", "white", "black", "gray"];
const result = arr.toString();
console.log(result);
// red,green,blue,white,black,gray

unshift()

  • 配列の最初に1つ以上の要素を追加し、新しい配列の長さを返す。
const arr = ["red", "green", "blue", "white"];
const result = arr.unshift("pink", "violet");
console.log(result);
// 6

console.log(arr);
[ 'pink', 'violet', 'red', 'green', 'blue', 'white' ]

values()

  • 配列の要素を順番とした新しいイテレーターオブジェクトを返す。
const arr = ["red", "green", "blue", "white"];
const iterator = arr.values();
for (const value of iterator) {
    console.log(value);
}
// red
// green
// blue
// white

連想配列

次に連想配列を紹介します。

assign()

  • 自身のプロパティをコピー元オブジェクトからコピー先オブジェクトにコピーする。
  • 変更されたコピー先オブジェクトを返す。
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);
console.log(target);
// { a: 1, b: 4, c: 5 }

console.log(returnedTarget);
// { a: 1, b: 4, c: 5 }

create()

  • 既存のオブジェクトを新しく生成されるオブジェクトのプロトタイプとして使用して、新しいオブジェクトを生成する。
const person = {
    isHuman: false,
    printIntroduction: function() {
        console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
    }
};

const me = Object.create(person);

me.name = 'Taro';
me.isHuman = true;

me.printIntroduction();
// "My name is Taro. Am I human? true"

defineProperties

  • オブジェクトに直接新しいプロパティを定義し(複数可能)、あるいは既存のプロパティを変更して、そのオブジェクトを返す。
const object = {};

Object.defineProperties(object, {
    property1: {
        value: "Taro",
        writable: true
    },
    property2: {
        value: "Jiro",
        writable: true
    },
});
console.log(object.property1);
console.log(object.property2);
// Taro
// Jiro

defineProperty

  • オブジェクトに直接新しいプロパティを定義し、あるいは既存のプロパティを変更して、そのオブジェクトを返す。
const object = {};

Object.definePropertiy(object, {
    property: {
        value: "Taro",
        writable: true
    }
});
console.log(object.property);
// Taro

entries()

  • 引数に与えたオブジェクトがもつ、文字列をキーとした列挙可能なプロパティからなる配列を返す。
const object = {
    name: "Taro",
    age: 42
};

for (const [key, value] of Object.entries(object)) {
    console.log(`${key}: ${value}`);
}
// Taro
// 42

freeze()

  • オブジェクトを凍結させる。
  • 凍結されたオブジェクトは変更できなくなる。
const object = {
    name: "Taro",
    age: 42
};

Object.freeze(object);
object.age = 100;
console.log(object.age);
// 42

fromEntries()

  • キーと値の組み合わせのリストをオブジェクトに変換する。
const entries = new Map([
    ["name", "Taro"],
    ["age", 42]
]);

const object = Object.fromEntries(entries);
console.log(object);
// { name: 'Taro', age: 42 }

getOwnPropertyDescriptor

  • 与えられたオブジェクトの特定のプロパティの構成を記述したオブジェクトを返す。
  • 指定したプロパティがオブジェクトにある場合は、プロパティ記述子を、それ以外の場合はundefinedを返す。
const object = {
    property: "Taro"
};

const descriptor = Object.getOwnPropertyDescriptor(object, 'property');
console.log(descriptor.configurable);
// true

console.log(descriptor.value);
// Taro

getOwnPropertyDescriptors()

  • 指定したオブジェクトのすべてのプロパティ記述子を返す。
const object = {
    property1: "Taro",
    property2: "Jiro"
};

const descriptors = Object.getOwnPropertyDescriptors(object);
console.log(descriptors.property1.value);
console.log(descriptors.property2.value);
// Taro
// Jiro

getOwnPropertyNames()

  • 与えられたオブジェクトのすべてキーの配列を返す。
const object = {
    property1: "Taro",
    property2: "Jiro"
};
console.log(Object.getOwnPropertyNames(object));
// [ 'property1', 'property2' ]

getOwnPropertySymbols()

  • 与えられたオブジェクト上で直接見つかるシンボルプロパティすべての配列を返す。
const object = {};
const a = Symbol('a');
const b = Symbol.for('b');

object[a] = 'localSymbol';
object[b] = 'globalSymbol';

const objectSymbols = Object.getOwnPropertySymbols(object);
console.log(objectSymbols.length);
// 2

console.log(objectSymbols);
// [ Symbol(a), Symbol(b) ]

getPrototypeOf()

  • 指定されたオブジェクトのプロトタイプ(内部プロパティの値)を返す。
const prototype = {};
const object = Object.create(prototype);
console.log(Object.getPrototypeOf(object) === prototype);
// true

hasOwnProperty()

  • オブジェクト自身が指定されたプロパティを持っているかどうかをbooleanで返す。
const object = {
    name: "Taro",
    age: 24
};
console.log(object.hasOwnProperty('name'));
// true

console.log(object.hasOwnProperty('gender'));
// false

is()

  • 2つの値が同一値であるかどうかを判定する。
const object1 = {
    name: "Taro",
    age: 24
};

const object2 = {
    name: "Taro",
    age: 24
};

const object3 = object1;
console.log(Object.is(object1, object2));
// false

console.log(Object.is(object1, object3));
//true

isExtensible()

  • オブジェクトが拡張可能であるか(新しいプロパティを追加することができるかどうか)を判定する。
const object1 = {
    name: "Taro",
    age: 24
};

const object2 = {
    name: "Taro",
    age: 24
};

Object.preventExtensions(object2);
console.log(Object.isExtensible(object1));
// true

console.log(Object.isExtensible(object2));
// false

isFrozen()

  • オブジェクトが凍結されているかどうかを判定する。
const object1 = {
    name: "Taro",
    age: 24
};

const object2 = {
    name: "Taro",
    age: 24
};

Object.freeze(object2);

console.log(Object.isFrozen(object1));
// false

console.log(Object.isFrozen(object2));
// true

isSealed()

  • オブジェクトが封印されているかどうかを判定する。
const object1 = {
    name: "Taro",
    age: 24
};

const object2 = {
    name: "Taro",
    age: 24
};

Object.seal(object2);

console.log(Object.isSealed(object1));
// false

console.log(Object.isSealed(object2));
// true

keys()

  • 指定されたオブジェクトが持つプロパティのキーの配列を返す。
const object = {
    name: "Taro",
    age: 24,
    gender: "man",
    hobby: "baseball"
};
console.log(Object.keys(object));
// [ 'name', 'age', 'gender', 'hobby' ]

preventExtensions()

すでにプロパティが追加されたオブジェクトで、新しいプロパティを抑制します。

const object = {
    name: "Taro",
    age: 24
};

Object.preventExtensions(object);

try {
    Object.defineProperty(object, "gender", {
        value: "man"
    });
} catch (e) {
    console.log(e);
}
// TypeError: Cannot define property gender, object is not extensible
//    at Function.defineProperty (<anonymous>)
//    at Object.<anonymous>

propertyIsEnumerable()

指定されたプロパティが列挙可能で、かつオブジェクト自身のプロパティであるかどうかを示す論理値を返す。

const object = {};
const arr = [];
object.name = "Taro";
arr[0] = "Taro";

console.log(object.propertyIsEnumerable('name'));
// true

console.log(object.propertyIsEnumerable('age'));
// false

console.log(arr.propertyIsEnumerable(0));
// true

console.log(arr.propertyIsEnumerable('age'));
// false

seal()

オブジェクトを封印して、新しいオブジェクトを追加することを抑制し、すべての既存のプロパティを設定変更不可にします。

現存するプロパティの値は、書き込み可能である限り変更できます。

const object = {
    name: "Taro",
    age: 42
};

Object.seal(object);
object.name = "Jiro";
console.log(object.name);
// Jiro

delete object.name;
console.log(object.name);
// Jiro

toString()

オブジェクトを表す文字列を返す。

function Dog(name) {
    this.name = name;
}

const dog = new Dog('poti');

Dog.prototype.toString = function dogToString() {
    return `${this.name}`;
};
console.log(dog.toString());
// expected output: "poti"

values()

指定されたオブジェクトが持つ列挙可能なプロパティの値を配列にして返す。

const object = {
    name: "Taro",
    age: 24,
    gender: "man",
    hobby: "baseball"
};
console.log(Object.values(object));
// [ 'Taro', 24, 'man', 'baseball' ]

参考

まとめ

この記事では、JavaScriptのコレクション関数をまとめてみました。
ここで紹介した関数をうまく使って、コーディングをしてみてください。
とても便利な関数が用意されていますので!!!
是非、いいねやコメントをお願いします。

Discussion