Gatsby Logo

[].slice.call()とは

2020-08-23

どうやら配列風オブジェクトを配列に変換する記法らしい。

JS
//配列風オブジェクト
const elms = document.querySelectorAll('.elm');

//配列に変換
const elmArr = [].slice.call(elms);

//配列なのでsliceメソッドを使える
elmArr.slice();

解説


🐳 NodeList

Document.querySelectorAll()メソッドは、配列風オブジェクトであるNodeListを取得する。
NodeListはArrayオブジェクトを継承していないので、slicepushなどのArray.prototypeが持つメソッドを使用できない。

JS
//配列風オブジェクト
const elms = document.querySelectorAll('.elm');

//配列ではないのでsliceメソッドを使えない
elms.slice();  // エラーが起こる

そのため、配列風オブジェクトでArray.prototypeメソッドを使用したい場合は、配列に変換する必要がある。


※ちなみにlengthプロパティは使用できる。(NodeListにもlengthプロパティが存在するため)
というか配列風オブジェクトはlengthを使えることが定義の1つらしい。

JS
// NodeListに含まれるノードの数を取得
console.log(elms.length);  

NodeList - Web API | MDN   👻  > forEach()とかも使えるのか..


🐳 [].slice

Array.prototype.slice()メソッドは、配列を切り抜くメソッド。
引数に何も指定しない場合、配列をshallow copyすることができる。

JS
const arr = ['hoge', 'fuga', 'piyo']

const sliceArr1 = arr.slice(2);
const sliceArr2 = arr.slice(1,3);
const copyArr = arr.slice();

console.log(sliceArr1);  // ['piyo']
console.log(sliceArr2);  // ['fuga', 'piyo']
console.log(copyArr);    // ['hoge', 'fuga', 'piyo']

Array.prototype.slice() - JavaScript | MDN

[].slice()と指定した場合は、空の配列をコピーすることになる。
が、ここでそれは重要ではなくて、「slice()の引数に何も指定しない場合、配列をshallow copyすることができる。」だけ覚えれば良いと思われ。


🐳 call()

Function.prototype.call()メソッドは、、説明が難しい。 MDNによると、

call() はあるオブジェクトに所属する関数やメソッドを、別なオブジェクトに割り当てて呼び出すことができます。

つまり最初の例の場合、Array.prototypeに所属するslice()メソッドを、引数に指定した配列風オブジェクトのelmsに割り当てて呼び出している。

JS
//配列風オブジェクト
const elms = document.querySelectorAll('.elm');

//そのままではslice()を使えないが、
elms.slice();  // エラー

//call()を使用して、配列風オブジェクトelmsを、配列として呼び出すことでslice()を使える
const elmArr = [].slice.call(elms);

よって実質elms.slice()が実行されることとなる。
引数なしのslice()メソッドは、配列のshallow copyと同義のため、elms(配列風オブジェクト)の中身をそのままコピーした配列が生成される。→目的の達成 🎉

■補足

call()は第2引数以降に、呼び出し先の関数に渡される引数を指定することができる。
つまり、この場合でslice()に引数を渡したい場合は、

JS
// 配列風オブジェクトを任意の形にsliceして配列に変換
const sliceElmArr = [].slice.call(elms, 1, 3);

のような形で指定ができる。


🐳 ES6以降では

ES6記法が使えるならArray.from()やスプレッド演算子を使えばおk

JS
//配列風オブジェクト
const elms = document.querySelectorAll('.elm');

//配列に変換
const elmArr1 = Array.from(elms);
const elmArr2 = [...elms];

🐳 おまけ知見


🐠 arguments

配列風オブジェクトの1つ。
すべての関数内(アロー関数を除く)で利用可能なローカル変数であり、関数の引数を参照することができる。 arguments - JavaScript | MDN

JS
const func = function(arg1, arg2) {
  console.log(arguments); // [1, 2]
};

func1(1, 2);

🐠 [].sliceは省略形

空配列[]を使用するのは省略形の書き方。slice()を使いたいだけなので以下の書き方でも良い。

JS
const elmArr = Array.prototype.slice.call(elms);

🐳 参考

Gatsby Tutorial Starter - Justin Formentin