なんとなくMDN(Mozilla Developer Network)のドキュメントを覗いてみると、そこには大量のメソッドが...!
「forで回せばどうにでもなるんや!」から卒業して、mapとかreduce使って今風というか関数型チックなコーディングをしたかったので、手始めにArrayのプロパティやらメソッドやらをまとめてみました。
サンプルコードはほぼMDNのドキュメントからのコピペです。
プロパティ
length
- Arrayの要素数を返す
const array = [1, 2, 3];
console.log(array.length); // 3
prototype
Array.isArray(Array.prototype); // true
メソッド(非prototype)
Array.from
- Arrayっぽいもの(Array, string, Set, Map etc...)からArrayを生成する
// Array-like object (arguments) to Array
function f() {
return Array.from(arguments);
}
f(1, 2, 3);
// [1, 2, 3]
// Any iterable object...
// Set
var s = new Set(["foo", window]);
Array.from(s);
// ["foo", window]
// Map
var m = new Map([[1, 2], [2, 4], [4, 8]]);
Array.from(m);
// [[1, 2], [2, 4], [4, 8]]
// String
Array.from("foo");
// ["f", "o", "o"]
// 第二引数にmapファンクションを渡すことで、Array.mapっぽいこともできる
Array.from([1, 2, 3], x => x + x);
// [2, 4, 6]
// Generate a sequence of numbers
Array.from({length: 5}, (v, k) => k);
// [0, 1, 2, 3, 4]
Array.isArray
- 任意のオブジェクトがArrayか否かを判別する
- SetやMapはfalse扱い
// 以下の呼び出しはすべてtrueを返す
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
// あまり知られていないもののArray.prototypeは配列:
Array.isArray(Array.prototype);
// 以下の呼び出しはすべてfalseを返す
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray(new Set());
Array.isArray(new Map());
Array.isArray({ __proto__: Array.prototype });
Array.of
-
まだ仕様が安定していないため非推奨- 仕様確定してました。MDNの日本語版の情報が古かったようです...
- 引数をつなげてArrayにする
Array.of(1); // [1]
Array.of(1, 2, 3); // [1, 2, 3]
Array.of(undefined); // [undefined]
Array.observe
- 廃止されました
メソッド(prototype)
Array.prototype.concat
const new_array = old_array.concat(value1[, value2[, ...[, valueN]]]);
- Arrayの連結
- 元のArrayは変更されない
- 何回も連結する場合は
Array.prototype.push.apply()
の方が速いらしい- concatは毎回コピーを作成するため
const alpha = ['a', 'b', 'c'],
numeric = [1, 2, 3];
const alphaNumeric = alpha.concat(numeric);
console.log(alphaNumeric); // Result: ['a', 'b', 'c', 1, 2, 3]
console.log(alpha); //alphaは変わらない: ['a', 'b', 'c']
// 3つのArrayを連結する時
const num1 = [1, 2, 3],
num2 = [4, 5, 6],
num3 = [7, 8, 9];
const nums = num1.concat(num2, num3);
console.log(nums);
// results in [1, 2, 3, 4, 5, 6, 7, 8, 9]
// 値を配列にぶち込むこともできる
const alphaNumeric2 = alpha.concat(1, [2, 3]);
console.log(alphaNumeric2);
// Result: ['a', 'b', 'c', 1, 2, 3]
Array.prototype.copyWithin
array.copyWithin(target, start[, end = this.length]);
- 「cppのmemmoveと同様の動きをする」...らしい
- 正直使いどころがよくわからない
- memmoveの解説
- 破壊的メソッドのため、取扱い注意
[1, 2, 3, 4, 5].copyWithin(-2);
// [1, 2, 3, 1, 2]
[1, 2, 3, 4, 5].copyWithin(0, 3);
// [4, 5, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, 3, 4);
// [4, 2, 3, 4, 5]
[1, 2, 3, 4, 5].copyWithin(0, -2, -1);
// [4, 2, 3, 4, 5]
[].copyWithin.call({length: 5, 3: 1}, 0, 3);
// {0: 1, 3: 1, length: 5}
// ES6 Typed Arrays are subclasses of Array
var i32a = new Int32Array([1, 2, 3, 4, 5]);
i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]
// On platforms that are not yet ES6 compliant:
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// Int32Array [4, 2, 3, 4, 5]
多分こんな動き
ary.copyWithin(x, y, z)
のとき、
ary[x] = ary[y]
ary[x + 1] = ary[y + 1]
- 2.をaryの末尾に到達するか、y + nがzになるまで繰り返す
...言語化するって難しい
Array.prototype.entries
const iterator = array.entries();
- Arrayのiteratorオブジェクトを取得する
- iteratorは[key, value]の形のようだ
const a = ['a', 'b', 'c'];
const iterator = a.entries();
console.log(iterator.next().value); // [0, 'a']
console.log(iterator.next().value); // [1, 'b']
console.log(iterator.next().value); // [2, 'c']
Array.prototype.every
const allPassed = array.every(callback[, thisObject]);
- Arrayの各要素に対してテスト関数を実行し、全てtrueだった時のみtrueを返す
- バリデーションとかに使える
const passed = [12, 5, 8, 130, 44].every((element, index, array) => {
return element >= 10;
});
console.log(passed); // false
Array.prototype.fill
arr.fill(value[, start = 0[, end = this.length]])
- 開始位置と終了位置を指定して、固定値で埋め尽くす
- 破壊的メソッド
[1, 2, 3].fill(4); // [4, 4, 4]
[1, 2, 3].fill(4, 1); // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1); // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2); // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN); // [1, 2, 3]
Array(3).fill(4); // [4, 4, 4]
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}
[1,2].fill(4, 2); // [1, 2] 元の配列に無いインデックスを指定しても無視される
Array.prototype.filter
const filteredArray = array.filter(callback[, thisObject]);
- Arrayの各要素に対してテスト関数を実行し、trueだったものだけの新しいArrayを作る
- 非破壊的なので安心
const filtered = [12, 5, 8, 130, 44].filter((element, index, array) => {
return element >= 10;
});
console.log(filtered); // [12, 130, 44]
Array.prototype.find
const element = arr.find(callback[, thisArg]);
- Arrayの各要素に対してテスト関数を実行し、trueだった要素を返す
- trueのものが複数当てはまる場合は最初に見つけたやつを返す
- オブジェクト配列に対して「特定のプロパティがhogeだったら」みたいなことするときは注意
- 見つからなかったらundefinedを返す
function isPrime(element, index, array) {
let start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) {
return false;
}
}
return element > 1;
}
console.log([4, 6, 8, 12].find(isPrime)); // undefined, not found
console.log([4, 5, 8, 12].find(isPrime)); // 5
// 複数当てはまる場合は最初のやつを返す
function isPrime(element, _index, _array) {
let start = 2;
while (start <= Math.sqrt(element.num)) {
if (element.num % start++ < 1) {
return false;
}
}
return element.num > 1;
}
const testArray = [
{id: 1, num: 4},
{id: 2, num: 5},
{id: 3, num: 7},
{id: 4, num: 8},
{id: 5, num: 12}
];
console.log(testArray.find(isPrime)); //{ id: 2, num: 5 }
Array.prototype.findIndex
- findと同様だけど、こっちはインデックスを返す
- 見つからなかったら-1を返す
Array.prototype.forEach
array.forEach(callback[, thisObj]);
- Arrayの各要素に対して関数を実行する
- Array.prototype界のスター選手(個人的感想)
- for文のbreakにあたることはできないので注意
- continueは途中でreturnすればできる
- 返値無いけど非破壊的
ffunction logArrayElements(element, index, array) {
if (index % 2 === 1) {
// インデックスが奇数なら飛ばす
// for文でいうところのcontinue;
return;
}
console.log("a[" + index + "] = " + element);
}
[2, 5, 9].forEach(logArrayElements);
// logs:
// a[0] = 2
// a[2] = 9
Array.prototype.includes
const boolean = array.includes(searchElement[, fromIndex]);
- Arrayに特定の要素が含まれているかをチェックする
- 仕様未確定
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
// 第二引数でArrayのどのインデックスから調べるかを指定する
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
[1, 2, NaN].includes(NaN); // true
Array.prototype.indexOf
const index = array.indexOf(searchElement[, fromIndex]);
- Arrayの要素のインデックスを調べる
- 判定は===演算子と同様の動き
- よってオブジェクトの配列に対してはfindIndexでやったほうがいい
- 見つからないと-1を返す
const array = [2, 5, 9];
let index = array.indexOf(2); // index は 0 となる
index = array.indexOf(7); // index は -1 となる
Array.prototype.join
const str = arr.join([separator = ',']);
- 配列の各要素を連結した文字列を返す
- デフォルトはカンマ区切り
- null や undefinedは空文字列に変換される
- CSV作りたいときに大活躍
const a = ["花", "太陽", "雨"];
const myVar1 = a.join(); // myVar1 に "花,太陽,雨" を代入
const myVar2 = a.join(", "); // myVar2 に "花, 太陽, 雨" を代入
const myVar3 = a.join("と"); // myVar3 に "花と太陽と雨" を代入
const myVar4 = a.join(''); // myVar4 に "花太陽雨" を代入
Array.prototype.keys
const iterator = array.keys();
- 配列の各インデックスのキーを含む新しい Array Iterator オブジェクトを返す
- ぶっちゃけよくわかってない
- 仕様未確定
const arr = ["a", "b", "c"];
const iterator = arr.keys();
console.log(iterator.next()); // { value: 0, done: false }
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
// 抜けのあるArrayからも漏れなくキーを取れる
const arr2 = ["a", , "c"];
const sparseKeys = Object.keys(arr2);
const denseKeys = [...arr2.keys()];
console.log(sparseKeys); // ['0', '2']
console.log(denseKeys); // [0, 1, 2]
Array.prototype.lastIndexOf
const index = array.lastIndexOf(searchElement[, fromIndex]);
- Arrayの要素のインデックスを後ろから調べる
- 判定の仕方はindexOfと同様
- 見つからなかったら-1を返すのも同様
const array = [2, 5, 9, 2];
const index = array.lastIndexOf(2); // index is 3
index = array.lastIndexOf(7); // index is -1
index = array.lastIndexOf(2, 3); // index is 3
index = array.lastIndexOf(2, 2); // index is 0
index = array.lastIndexOf(2, -2); // index is 0
index = array.lastIndexOf(2, -1); // index is 3
Array.prototype.map
const mapedArray = arr.map(callback[, thisArg]);
- Arrayの各要素に対して関数を実行し、その結果を集めた新しいArrayを返す
- for文で言うところのcontinueやbreakはできない
- forEachの感覚で途中でreturnするとundefinedが入り込む
- 処理したくない要素は予めfilterで排除しておくこと
const numbers = [1, 4, 9];
const doubles = numbers.map(function(num) {
return num * 2;
});
// doubles is now [2, 8, 18]
// numbers is still [1, 4, 9]
// 途中でreturnするとundefinedが入り込む
const mapped = [1, 2, 3, 4].map((element, index, array) => {
if (index % 2 === 0) {
return;
}
return element;
});
console.log(mapped); //[ undefined, 2, undefined, 4 ]
Array.prototype.pop()
const tail = array.pop();
- Arrayの最後の要素を返しつつ、Arrayから削除する
- 空のArrayに対して使った場合はundefinedが返る
- 「末尾の値が欲しい時」より「末尾を消したい時」に出番がある気がする
- 当然破壊的
const myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];
console.log(myFish); // ['angel', 'clown', 'mandarin', 'sturgeon']
const popped = myFish.pop();
console.log(myFish); // ['angel', 'clown', 'mandarin' ]
console.log(popped); // 'sturgeon'
Array.prototype.push()
const newLength = array.push(element1, ..., elementN)
- Arrayの末尾に要素を追加する
- 引数を複数与えればそのままの順番で追加される
- 実は要素追加後の新しいlengthが返ってくる
- push.applyを使ってArrayの連結もできる
- その場合push.applyの第一引数のArrayが変更される
- concatと同じノリで
const newArray = Array.prototype.push.apply(array1, array2);
とかやると死ぬ
- 至極当然破壊的
const sports = ['soccer', 'baseball'];
const total = sports.push('football', 'swimming');
console.log(sports); // ['soccer', 'baseball', 'football', 'swimming']
console.log(total); // 4
const vegetables = ['parsnip', 'potato'];
const moreVegs = ['celery', 'beetroot'];
// 1 つ目の配列に 2 つ目の配列をマージさせます
// vegetables.push('celery', 'beetroot'); と同じ結果になります
Array.prototype.push.apply(vegetables, moreVegs);
console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot']
Array.prototype.reduce
const result = array.reduce(callback[, initialValue]);
- 各要素に対して順番に関数を適用して、単一の値を導く
- 数値配列の合計を求めたりするときに便利
- 地味に有能な子
const sum = [0,1,2,3,4].reduce((previousValue, currentValue, index, array) => {
return previousValue + currentValue;
});
console.log(sum); // 10
previousValue, currentValueってなんやねん
↑の例の場合
- Arrayの最初の2つの要素を使って、previousValue = 0, currentValue = 1として計算、 0 + 1 = 1がreturnされる
- previousValue = 1(1.の計算結果), currentValue = 2(Arrayの3つめの要素)として計算、 1 + 2 = 3がreturnされる
- previousValue = 3(2.の計算結果), currentValue = 3(Arrayの4つめの要素)として計算、 3 + 3 = 6がreturnされる
- previousValue = 6(3.の計算結果), currentValue = 4(Arrayの5つめの要素)として計算、 6 + 4 = 10がreturnされる
- Arrayの末尾まで到達したので、最終結果として10がreturnされる
↓initialValueを指定した場合
const sum = [0,1,2,3,4].reduce((previousValue, currentValue, index, array) => {
return previousValue + currentValue;
}, 5);
console.log(sum); // 15
- previousValue = 5(initialValue), currentValue = 0(Arrayの最初の要素)として計算、 5 + 0 = 5がreturnされる
- previousValue = 5(1.の計算結果), currentValue = 1(Arrayの2つめの要素)として計算、 5 + 1 = 6がreturnされる
- previousValue = 6(2.の計算結果), currentValue = 2(Arrayの3つめの要素)として計算、 6 + 2 = 8がreturnされる
- previousValue = 8(3.の計算結果), currentValue = 3(Arrayの4つめの要素)として計算、 8 + 3 = 11がreturnされる
- previousValue = 11(4.の計算結果), currentValue = 4(Arrayの5つめの要素)として計算、 11 + 4 = 15がreturnされる
- Arrayの末尾まで到達したので、最終結果として15がreturnされる
実際に一回コードを書いてみればなんとなくわかるかと思います
Array.prototype.reduceRight
const result = array.reduceRight(callback[, initialValue]);
- reduceと同じことを、Arrayの末尾から順番にやる
Array.prototype.reverse
array.reverse()
- Arrayの順番を逆転させる
- 破壊的メソッド
const myArray = [1, 2, 3];
myArray.reverse(); //[3, 2, 1]
Array.prototype.shift
const top = array.shift();
- Arrayの先頭の要素を返しつつArrayから削除する
- 先頭の要素を取得できることより、先頭の要素が削除されることがミソ
- 取得したいだけなら
array[0]
でいいし、arrayが変更されないから安全
- 取得したいだけなら
- 破壊的
const myFish = ["angel", "clown", "mandarin", "surgeon"];
console.log("myFish 処理前: " + myFish);
//myFish 処理前: ["angel", "clown", "mandarin", "surgeon"]
const shifted = myFish.shift();
console.log("myFish 処理後: " + myFish);
//myFish 処理後: ["clown", "mandarin", "surgeon"]
console.log("取り除いた要素: " + shifted);
//取り除いた要素: angel
Array.prototype.slice
const sliced = array.slice(begin[,end]) ;
- インデックスを指定してArrayの一部を抜き出す
- endを指定しなかった場合はbeginから末尾まで
-
endに指定したインデックス自体は対象外
-
const sliced = array.slice(1, 3);
とした場合、slicedにはarray[1],array[2]は含まれるがarray[3]は含まれない - この仕様はトラップすぎると思う
-
// Our good friend the citrus from fruits example
const fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
const citrus = fruits.slice(1, 3);
// puts --> ["Orange","Lemon"]
Array.prototype.some
const someElementPassed = array.some(callback[, thisObject]);
- Arrayの各要素に対してテスト関数を実行し、一つでもtrueだったらtrueを返す
- every -> 全て, some -> どれか、つまりそういうことだ
Array.protoype.sort
array.sort(compareFunction);
- compareFunctionにもとづいてarrayをソートする
- compareFunctionを指定しなかった場合は、各要素を無理やりStringにして辞書順にソートする
- "80"が"9"の前に来ちゃうぞ!
- 破壊的メソッド
忘れやすいcompareFunctionの仕様
- 引数a, bはArrayの中の隣り合う2要素
- compareFunction(a, b) < 0 のとき -> aをbより先に持ってくる
- compareFunction(a, b) === 0 のとき -> 何もしない
- ECMAScript標準では非推奨
- compareFunction(a, b) > 0 のとき -> aをbより後に持ってくる
というわけで、何かの基準で比較して、1 or -1を返すようにするのがベター
Array.prototype.splice
array.splice(index, howMany, [element1][, ..., elementN]);
- Arrayから要素を削除しつつ、代わりに新しい要素をぶち込む
- array[index]から順番にhowMany個の要素を消して、代わりにelement1~elementNをぶち込む
- 当然要素数が変わることもありうる
- Array.prototype.sliceと間違えたら大惨事
- 一つのメソッドで色々やりすぎな気がしなくもない
- これでもかというぐらい破壊的なメソッド
const myFish = ["angel", "clown", "mandarin", "surgeon"];
console.log("myFish: " + myFish); // myFish: angel,clown,mandarin,surgeon
let removed = myFish.splice(2, 0, "drum");
console.log("1 つ追加した後: " + myFish); // 1 つ追加した後: angel,clown,drum,mandarin,surgeon
console.log("取り除いたのは: " + removed);// 取り除いたのは:
removed = myFish.splice(3, 1);
console.log("1 つ取り除いた後: " + myFish); // 1 つ取り除いた後: angel,clown,drum,surgeon
console.log("取り除いたのは: " + removed); // 取り除いたのは: mandarin
removed = myFish.splice(2, 1, "trumpet");
console.log("1 つ置き換えた後: " + myFish); // 1 つ置き換えた後: angel,clown,trumpet,surgeon
console.log("取り除いたのは: " + removed); // 取り除いたのは: drum
removed = myFish.splice(0, 2, "parrot", "anemone", "blue");
console.log("2 つ置き換えた後: " + myFish); // 2 つ置き換えた後: parrot,anemone,blue,trumpet,surgeon
console.log("取り除いたのは: " + removed); // 取り除いたのは: angel,clown
Array.prototype.toLocaleString
const locale = array.toLocaleString();
- Arrayの各要素を連結して文字列にする、そしてローカライズする
- すごく...影が薄いです...
const number = 1337;
const date = new Date();
const myArr = [number, date, 'foo'];
const str = myArr.toLocaleString();
console.log(str);
// logs '1337,6.12.2013 19:37:35,foo'(ドイツで実行した場合)
Array.prototype.toSource
const source = array.toSource();
- Arrayのソースを返す
- 非標準なので基本的に使っちゃダメ
- デバッグ目的で使う可能性が微粒子レベルで存在する
const alpha = new Array("a", "b", "c");
alpha.toSource(); // ["a", "b", "c"] が返る
Array.prototype.toString
const string = array.toString();
- Arrayの各要素をカンマ区切りで連結にして文字列にする
- join()と同じ
JavaScript 1.8.5 以降、および ECMAScript 第 5 版では、toString() メソッドは一般化されており、全てのオブジェクトで使用可能となっています。オブジェクトが join() メソッドを持つ場合はそれが呼び出され、その値が返されます。そうでない場合は Object.prototype.toString() が呼び出され、その結果の値が返されます。
Mozillaのドキュメントより引用
Array.prototype.unshift
const newLength = array.unshift([element1[, ...[, elementN]]])
- Arrayの先頭に要素を追加する
- push, pop, shift, unshiftで混乱するのは誰もが通る道
- こいつも何気に要素追加後のlengthを返す
- 破壊的
const arr = [1, 2];
arr.unshift(0); //result of call is 3, the new array length
//arr is [0, 1, 2]
arr.unshift(-2, -1); // = 5
//arr is [-2, -1, 0, 1, 2]
arr.unshift( [-3] );
//arr is [[-3], -2, -1, 0, 1, 2]
Array.prototype.values
const eArr = array.values();
- valueを含むイテレータを返す
- JavaScriptでイテレータを使ってるところを殆ど見たこと無いのでなんとも言えない
const arr = ['w', 'y', 'k', 'o', 'p'];
const eArr = arr.values();
console.log(eArr.next().value); // w
console.log(eArr.next().value); // y
console.log(eArr.next().value); // k
console.log(eArr.next().value); // o
console.log(eArr.next().value); // p