※スマホ対応はしてません。

タグ: 配列

配列を「開いて」使うスプレッド演算子。(現代的JavaScriptおれおれアドベントカレンダー2017 – 18日目)

カテゴリー: JavaScript

現代的JavaScriptおれおれアドベントカレンダー2017 – 18日目

概要

配列をばらばらの配列要素だったことにして使えるやつです。

const arr = [1, 2, 3];

const arr2 = [0, ...arr];  // => [0, 1, 2, 3]

使い方

カンマ , 区切りでいろいろ書くところへ、 ...arr のようにすると、その配列の中身をばらばらに書いたかのような状態に展開してくれます。

配列とか、

const arr0 = [1, 2, 3];

const arr1 = [0, ...arr];  // => [0, 1, 2, 3]

関数とか。

function foo(a, b, c) {
  console.log(a, b, c);
}

const arr = [1, 2, 3];
foo(...arr);  // 1, 2, 3

途中でも、いくつでも

残余引数とかは末尾でしか使えなかったんですが、展開する分には十分明瞭なので、どこでもいくつでも使えます。

const arr1 = [1, 2, 3];
const arr2 = [4, 5];
const arr3 = [];

const all = ['|', ...arr1, '|', ...arr2, '|', ...arr3, '|'];  // => [ '|', 1, 2, 3, '|', 4, 5, '|', '|' ]

配列の中の配列

... を付けないとただの入れ子になります。そりゃそうじゃ。

const arr0 = [1, 2, 3];

const arr1 = [0, arr0];  // => [0, [1, 2, 3]]
const arr2 = [0, ...arr0];  // => [0, 1, 2, 3]

配列の複製

残余代入の方でも同じようなことやったけど、変数に格納する必要がない分こっちの方が良いかも。

const arr1 = [1, 2, 3];

function checkCloned(arr2) {
  console.log(arr1);
  console.log(arr2);
  console.log(arr1 === arr2);
}

checkCloned([...arr1]);
[ 1, 2, 3 ]
[ 1, 2, 3 ]
false

配列の結合

Array#conat() の代わりに使えそうです。

const arr1 = [1, 2, 3];
const arr2 = [4, 5];

const all1 = arr1.concat(arr2);  // => [1, 2, 3, 4, 5]
const all2 = [...arr1, ...arr2];  // => [1, 2, 3, 4, 5]

先頭項目を入れ替える

const arr = [1,2,3,4,5];

const [, ...secondAndLater] = arr;
const arr2 = [99, ...secondAndLater];  // => [99, 2, 3, 4, 5];

書いてはみたけど何に使えるかな。

オブジェクトのスプレッド

オブジェクトの残余代入と同様、ES2017までにはまだ存在していない未来仕様です。ES2018に入りそう。

const obj1 = { a: 1 };
const obj2 = { ...obj1 };

執筆時点でChrome、Firefoxとあと手元のNode.js v8.5で動いてます。

一方babel-preset-envのv1.6.1では対応してないっぽい。

SyntaxError: /path/to/project/main.js: Unexpected token (2:15)
  1 | const obj1 = { a: 1 };
> 2 | const obj2 = { ...obj1 };
    |                ^

(細かいバージョンは調べてません。)

Reactで使う

JSXの仕様なのでESのものではないんだけど、似たようなものなので紹介しておきます。あ、これオブジェクトの展開してるね。

you can use ... as a “spread” operator

const Button = props => {
  const { kind, ...other } = props;
  const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
  return <button className={className} {...other} />;
};

Reactは普段使いしてないです。なんか違ってたらごめんなさい、教えてください。

その他

名前

みんな「スプレッド演算子 (spread operator)」と呼んでるけど、仕様書にそういう表現ないね。

あと配列の方は “SpreadElement” という名前が出てきてるんだけど、関数引数の方は特に名前が付いてもいない。

参考

  • ECMAScript® 2017 Language Specification
    • 12.2.5 Array Initializer … “SpreadElement” 配列のスプレッド演算子の記法
    • 12.2.5.2 Runtime Semantics: ArrayAccumulation … スプレッド演算子の処理
    • 12.3 Left-Hand-Side Expressions … 関数呼び出しの ArgumentList
    • 12.3.4 Function Calls
    • 12.3.6.1 Runtime Semantics: ArgumentListEvaluation … “…AssignmentExpression” とかの解釈
    • 9.4.4 Arguments Exotic Objects … arguments
  • スプレッド演算子 – JavaScript | MDN

分割代入、配列も画期的。(現代的JavaScriptおれおれアドベントカレンダー2017 – 15日目)

カテゴリー: JavaScript

現代的JavaScriptおれおれアドベントカレンダー2017 – 15日目

概要

オブジェクトとかでまとまってもらえる情報を、最初からバラバラにしちゃうやつです。配列でも使えます。

const arr = ['https:', 'ginpen.com', '/about'/];

const [protocol, host, path] = arr;
console.log(protocol);  // => "https:"
console.log(host);  // => "ginpen.com"
console.log(path);  // => "/about/"

String#match() で猛威を振るいそう。(?)

使い方

左辺にしかく括弧 [ … ] で括って、初期化なり代入なりする変数の名前を書きます。

const arr = [11, 22];

const [a, b] = arr;
console.log(a);  // => 11
console.log(b);  // => 22

順序左側の順序と右側の順序が一致します。

いらない値を飛ばす

カンマ , だけ書いて変数名を省略すると、そこの位置の値を飛ばします。

const arr = [11, 22, 33];

const [a, , b] = arr;
console.log(a);  // => 11
console.log(b);  // => 33

残りの値をまとめる

... を使って「残り」を全てひとつの新しい配列に突っ込むことができます。

const arr = [11, 22, 33, 44];

const [first, ...rest] = arr;
console.log(first);  // => 11
console.log(rest);  // => [22, 33, 44]

この ... は関数の仮引数でも使えます。別稿参照。

初期値

オブジェクトのやつと同様、 = で初期値を設定できます。

const arr = [-1, undefined, -3];

const [a = 11, b = 22, c = 33, d = 44] = arr;
console.log(a);  // => -1
console.log(b);  // => 22
console.log(c);  // => -2
console.log(d);  // => 44

入れ子

これもオブジェクトのやつと同様。

consr arrrr = ['1', ['2-1', ['2-2-1']], 3];

const [a, [, [x]], c] = arrrr;
console.log(a);  // => '1'
console.log(x);  // => '2-2-1'

もちろんオブジェクトと組み合わせて使うこともできます。

const data = { names: ['Martin', 'Luther', 'King'] };

const { names: [first, , family] } = data
console.log(first);  // => 'Martin'
console.log(family);  // => 'King'

String#match() と組み合わせる

諸々便利かなと思います。

例えば日付を分解する。

const rxDate = /(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)/;

const sDate = '2017-12-15 10:05:00';

const [, year, month, date, hours, minutes, seconds] = sDate.match(rxDate);
console.log(year);  // => "2017"
console.log(hours);  // => "10"

結果の先頭には条件に合致した全体が入ってくるけど、今回いらないので、値を捨てます。

変数の中身を入れ替える

MDNに載ってたけどあんまり使わない気がする。

let a = 'A';
let b = 'B';

[a, b] = [b, a];
console.log(a);  // => "B"
console.log(b);  // => "A"

んー何かのアルゴリズムとかでこういうことしたっけかな。

引数とか?の先頭とそれ以外を分ける

例はNode.jsの方ですけども、なんかこういうのすることもあるかもしれない。

const { spawn } = require('child_process');

const input = 'ls -a -l /var/log';

const [command, ...args] = input.split(' ');
spawn(command, args)
    .stdout.on('data', (data) => {
        console.log(data.toString());
    });

その他

省略のカンマ ,

仕様書では “elision” と呼称されているようです。

主な意味: (母音・音節などの)省略

参考

配列の .lengthは代入できる(JavaScript おれおれ Advent Calendar 2011 – 10日目)

カテゴリー: JavaScript, Web

JavaScript おれおれ Advent Calendar 2011 – 10日目

配列はプロパティ .lengthを持っていますが、実はこれ、現在の配列項目数を取得するだけじゃなくて、設定する事もできたりします。

var arr = [];
console.log(arr.length);  // => 0

arr.length = 5;
console.log(arr.length);  // => 5
console.log(arr.join(','));  // => ",,,,"
console.log(arr[0]);  // => undefined

増えた分はundefinedが入ります。

(さらに…)