Posts ほんの小さなJavaScriptの知見集
Post
Cancel

ほんの小さなJavaScriptの知見集

スプレッド演算子

ドット3つのというような演算子のこと。

配列リテラル

1
2
3
var d1 = [1, 2, 3];
var d2 = [4, 5, d1];
console.log(d2);

これだと、当然ですが

1
[ 4, 5, [ 1, 2, 3 ] ]

と出力されます。

しかし、

1
2
3
var d1 = [1, 2, 3];
var d2 = [4, 5, ...d1];
console.log(d2);

とすれば、

1
[ 4, 5, 1, 2, 3 ]

となります。

これを応用すると

1
2
3
4
var d1 = [1, 2, 3];
var d2 = [4, 5];
d1.push(...d2);
console.log(d1);

を実行すると

1
[ 1, 2, 3, 4, 5 ]

という感じで、配列の合体もできます。

関数リテラル

1
2
3
4
5
6
function func(a, b, c, d, e) {
    console.log(arguments);
}
var d1 = [1, 2, 3];
var d2 = [4, 5, ...d1]; // →[ 4, 5, 1, 2, 3 ]
func(...d2);

これを実行すると

1
{ '0': 4, '1': 5, '2': 1, '3': 2, '4': 3 }

関数が呼ばれると自動で作成されるargumentsはオブジェクトで、第1引数(添え字0)は4で・・・となっています(オブジェクトなので、当然arguments[0]でアクセス出来ます)。

もしスプレッド演算子を使わないで、

1
2
3
4
5
6
function func(a, b, c, d, e) {
    console.log(arguments);
}
var d1 = [1, 2, 3];
var d2 = [4, 5, ...d1]; // →[ 4, 5, 1, 2, 3 ]
func(d2);

のように実行すると

1
{ '0': [ 4, 5, 1, 2, 3 ] }

第1引数1つに配列が受け取られちゃいます。

分割代入

1
2
3
var options = [];
[a, b, ...options] = [1, 2, 3, 4, 5];
console.log(options);

のように受けると、出力されるoptions

1
[ 3, 4, 5 ]

となり、残りをしっかり受け取っています。これを応用すると

1
2
3
4
5
function func2(a, b, ...options) {
    console.log(options);
}
var args = [5, 4, 3, 2, 1];
func2(...args);

関数の引数にも利用できて、便利かもしれません。

オブジェクトリテラル

オブジェクトでもを使うことができます。ただしオブジェクトの場合、仕様がまだFixしていないようです。とはいえ、Nodeでは使うことができます(当方のVersion 8系で、バージョンにもよるでしょうが)。ただ、Babelを利用しているような場合、次のようなことが必要です。

1
babel --presets stage-1 -o spread_operator.bundle.js spread_operator.js

のように、optionの–presets stage-1が必要のようです。

おっと、stage-1のプリセットを使うために、npmインストールも行う必要があります。

1
$ npm install --save-dev babel-preset-stage-1

も実行してください(今回はnodeでやっていますw)。

これらが使えると、少し便利になります。

例えば、次のようなobject2つがあって、プロパティを追加したい場合があります。

1
2
3
4
5
6
7
8
9
10
11
12
var nested2 = {
    prop3: 30,
    prop4: 40
};

var opt = {
    id: 1,
    nested: {
        prop1: 10,
        prop2: 200
    }
};

つまり、下のoptのnestedプロパティのオブジェクトに、nested2の2つのプロパティを加えて

1
2
3
4
5
6
7
8
9
var opt = {
    id: 1,
    nested: {
        prop1: 10,
        prop2: 200,
        prop3: 30,
        prop4: 40
    }
};

のようにしたい場合2つのObjectをマージするのような方法もありますが、プロパティを加えたい場合はスプレッド演算子を使えば簡単です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var nested2 = {
    prop3: 30,
    prop4: 40
};

var opt = {
    id: 1,
    nested: {
        prop1: 10,
        prop2: 200,
        ...nested2
    }
};
console.log(opt);

これですと

1
2
{ id: 1,
  nested: { prop1: 10, prop2: 200, prop3: 30, prop4: 40 } }

となり、目的を達成できます。もし、がなくて

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var nested2 = {
    prop3: 30,
    prop4: 40
};

var opt = {
    id: 1,
    nested: {
        prop1: 10,
        prop2: 200,
        nested2
    }
};
console.log(opt);

これですと

1
2
{ id: 1,
  nested: { prop1: 10, prop2: 200, nested2: { prop3: 30, prop4: 40 } } }

となって、新しいキーができちゃうし、

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var nested = {
    prop3: 30,
    prop4: 40
};

var opt = {
    id: 1,
    nested: {
        prop1: 10,
        prop2: 200,
    },
    nested
};
console.log(opt);

単に後がちで、

1
{ id: 1, nested: { prop3: 30, prop4: 40 } }

のように、上書きされちゃうので、使えません。

このセクションはこれにて終了。

2つのObjectをマージする、Object.assign、_.merge、$.extend

デフォルトのオプションを決めておき、ユーザがそのオプションを別途用意してデフォルトを書き換えるということがあります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var opt = {
    op1: 1,
    op2: false,
    op3: "Hello!"
};

var userOpt = {
    op2: true,
    op3: "Ohayo!"
};

var mergedOpt = Object.assign(opt, userOpt );

console.log(mergedOpt);

これを実行すれば、

1
{ op1: 1, op2: true, op3: 'Ohayo!' }

というようにマージされます。Object.assignは、ただし、注意が必要です。

次のように、ネストしたObjectがあったような場合です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var opt = {
    id: 1,
    nested: {
        prop1: 10,
        prop2: 200
    }
};
var userOpt = {
    id: 2,
    nested: {
        prop2: 20,
        prop3: 30
    }
};
var mergedOpt = Object.assign(opt, userOpt );
console.log(mergedOpt);

Object.assignはリカーシブには行ってくれないので、次のようになってしまいます。

1
{ id: 2, nested: { prop2: 20, prop3: 30 } }

これはnestedキーの値を後ろので、上書きしてしまっているようです。prop3を追加したいのにです。

本来

1
{ id: 2, nested: { prop1: 10, prop2: 20, prop3: 30 } }

になって欲しいはず(これで何時間も損したことが・涙)。

これを避けるには、lodashのextendやjQueryのextendを利用する方法があります。lodashの場合次のようにしてみると、成功します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var opt = {
    id: 1,
    nested: {
        prop1: 10,
        prop2: 200
    }
};
var userOpt = {
    id: 2,
    nested: {
        prop2: 20,
	prop3: 30
    }
};
var _ = require('lodash');
var mergedOpt = _.merge(opt, userOpt);
console.log(mergedOpt);

これだと

1
{ id: 2, nested: { prop1: 10, prop2: 20, prop3: 30 } }

でお望みのもの。

コマンドラインでjQueryを使うのに結構手間取ってしまった。*jquery=3.2.1, jsdom = 10.1.0*でしか、動かなかった。ふう。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
jsdom = require("jsdom");
const { JSDOM } = jsdom;
const { window } = new JSDOM(`<!DOCTYPE html>`);
const $ = require('jquery')(window);

var opt = {
    id: 1,
    nested: {
        prop1: 10,
        prop2: 200
    }
};
var userOpt = {
    id: 2,
    nested: {
        prop2: 20,
	prop3: 30
    }
};
var mergedOpt = $.extend(true, opt, userOpt);
console.log(opt);

一応jQueryでも確認しました(extnd第1引数のtrueは必須です)。

このセクションはこれにて終了。

シェア
#内容発言者

thisにまつわる話し

CORSをめぐって

坂井和郎