Created
March 25, 2020 16:52
-
-
Save okunokentaro/e6aae7eaa024f296bf55e043fc9cd62d to your computer and use it in GitHub Desktop.
Destructuring assignmentのご利用は計画的に
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2015/08/03 にQiitaに投稿した記事のアーカイブです | |
--- | |
@armorik83です。ES2015に勢いがあるので本日2本目の記事です(前の記事は[ESLint 1.0.0新ルールまとめ](http://qiita.com/armorik83/items/228b97bee25aa33c9850))。 | |
# ES2015の活用 | |
今、業務ではBabelの許可が出ているので、フルにES2015(ES6とも呼ばれていました)を活用しています。Class構文や`Import`はTypeScript経験も手伝ってもはや当たり前になっていますが、最近使い始めたDestructuring assignmentは迂闊に使うと(特にチーム内での)混乱に繋がるぞ…と危険視し始めたので、挙動を確認しておきます。 | |
# Destructuring assignment | |
> https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment | |
ブラウザのサポートはまだまだで、現状Babelの変換結果に頼っている状態です。なお個人的な感想ですが、Babel開発者はPRなどで送られた仕様外の挙動は容赦なくrejectするため、準拠度合いには一定の信頼を持っています。 | |
以下の挙動確認はすべてBabel 5.8.xによるものです。[Babel Try it out](https://babeljs.io/repl/#?experimental=false&evaluate=true&loose=false&spec=false&code=) | |
## 構文例 | |
```js:es6.js | |
const [a, b] = [1, 2]; | |
const [c, d, ...rest] = [1, 2, 3, 4, 5]; | |
const {e, f} = {e: 1, f: 2}; | |
``` | |
```js:es6.js | |
function f({a, b}) { | |
return a + b; | |
} | |
f({a: 1, b: 2}); // 3 | |
``` | |
```js:es6.js | |
class Person { | |
constructor({first, last}) { | |
this.first = first; | |
this.last = last; | |
} | |
} | |
const p = new Person({first: 'John', last: 'Appleseed'}); | |
``` | |
# 様々なケースを試す | |
今回は挙動を検証したいだけの記事なので、この構文の何が便利かという疑問については別の機会とします。 | |
## 1 | |
```js | |
function f({a, b}) { | |
return a + b; | |
} | |
f({a: 1, b: 2}); // 3 | |
``` | |
### 1-1. aに初期値 | |
```js | |
function f({a = 3, b}) { | |
return a + b; | |
} | |
f({a: 1, b: 2}); // 3 | |
f({b: 2}); // 5 | |
f({}); // null | |
f(); // Cannot read property 'a' of undefined | |
``` | |
### 1-2. a, bに初期値 | |
```js | |
function f({a = 3, b = 5}) { | |
return a + b; | |
} | |
f({a: 1, b: 2}); // 3 | |
f({a: 1}); // 6 | |
f({b: 2}); // 5 | |
f({}); // 8 | |
f(); // Cannot read property 'a' of undefined | |
``` | |
### 1-3. {a, b}に初期値、argument[0]自体に初期値(空オブジェクト) | |
```js | |
function f({a = 3, b = 5} = {}) { | |
return a + b; | |
} | |
f({a: 1, b: 2}); // 3 | |
f({a: 1}); // 6 | |
f({b: 2}); // 5 | |
f({}); // 8 | |
f(); // 8 | |
``` | |
### 1-4. {a, b}に初期値、argument[0]自体に初期値(プロパティ値指定) | |
```js | |
function f({a = 3, b = 5} = {a: 7, b: 11}) { | |
return a + b; | |
} | |
f({a: 1, b: 2}); // 3 | |
f({a: 1}); // 6 | |
f({b: 2}); // 5 | |
f({}); // 8 | |
f(); // 18 | |
``` | |
この辺りから、Destructuring assignmentを学習していない者には厳しい構文になってきます。 | |
## 2 | |
```js | |
function f({a, b, c, d}) { | |
return a + b + c + d; | |
} | |
f({a: 1, b: 2, c: 3, d: 5}); // 11 | |
``` | |
### 2-1. 2つに分割 | |
```js | |
function f({a, b}, {c, d}) { | |
return a + b + c + d; | |
} | |
f({a: 1, b: 2}, {c: 3, d: 5}); // 11 | |
f({c: 3, d: 5}, {a: 1, b: 2}); // null | |
``` | |
### 2-2. 初期値を指定 | |
```js | |
function f({a = 7, b = 11}, {c = 13, d = 17}) { | |
return a + b + c + d; | |
} | |
f({a: 1, b: 2}, {c: 3, d: 5}); // 1 + 2 + 3 + 5 = 11 | |
f({a: 1}, {c: 3}); // 1 + 11 + 3 + 17 = 32 | |
f({}, {}); // 7 + 11 + 13 + 17 = 48 | |
f({}); // Cannot read property 'c' of undefined | |
f(); // Cannot read property 'a' of undefined | |
``` | |
### 2-3. argument[0]自体に初期値を指定 | |
```js | |
function f({a = 7, b = 11} = {a: 19, b: 23, c: 29, d: 31}, {c = 13, d = 17}) { | |
return a + b + c + d; | |
} | |
f({a: 1, b: 2}, {c: 3, d: 5}); // 1 + 2 + 3 + 5 = 11 | |
f({a: 1}, {c: 3}); // 1 + 11 + 3 + 17 = 32 | |
f({}, {}); // 7 + 11 + 13 + 17 = 48 | |
f(void 0, {}); // 19 + 23 + 13 + 17 = 72 | |
f({}); // Cannot read property 'c' of undefined | |
f(); // Cannot read property 'c' of undefined | |
``` | |
### 2-4. argument[0], argument[1]自体に初期値を指定 | |
```js | |
function f({a = 7, b = 11} = {a: 19, b: 23, c: 29, d: 31}, {c = 13, d = 17} = {a: 37, b: 41, c: 43, d: 47}) { | |
return a + b + c + d; | |
} | |
f({a: 1, b: 2}, {c: 3, d: 5}); // 1 + 2 + 3 + 5 = 11 | |
f({a: 1}, {c: 3}); // 1 + 11 + 3 + 17 = 32 | |
f({}, {}); // 7 + 11 + 13 + 17 = 48 | |
f(void 0, {}); // 19 + 23 + 13 + 17 = 72 | |
f({}); // 7 + 11 + 43 + 47 = 108 | |
f(); // 19 + 23 + 43 + 47 = 132 | |
``` | |
# 3 | |
## 3-1. Object初期値と引数初期値を揃える | |
```js | |
function f({a = 1, b = 2} = {a: 1, b: 2}) { | |
return a + b; | |
} | |
f({a: 3, b: 5}); // 8 | |
f({a: 3}); // 5 | |
f({b: 5}); // 6 | |
f({a: null}); // 2 | |
f({b: null}); // 1 | |
f({a: void 0}); // 3 | |
f({b: void 0}); // 3 | |
f({}); // 3 | |
f(); // 3 | |
function g(a = 1, b = 2) { | |
return a + b; | |
} | |
g(3, 5); // 8 | |
g(3); // 5 | |
g(5); // 7 | |
g(void 0, 5); // 6 | |
g(null, 5); // 5 | |
g(); // 3 | |
``` | |
## 3-2. TypeScriptの場合 | |
```ts:typescript.ts | |
interface I { | |
a?: number; | |
b?: number; | |
} | |
function f({a = 1, b = 2}: I = {a: 1, b: 2}) { | |
return a + b; | |
} | |
f({a: 3, b: 5}); // 8 | |
f({a: 3}); // 5 | |
f({b: 5}); // 6 | |
f({a: null}); // 2 | |
f({b: null}); // 1 | |
f({a: void 0}); // 3 | |
f({b: void 0}); // 3 | |
f({}); // 3 | |
f(); // 3 | |
``` | |
TypeScriptでも`interface`を指定すれば書ける。 | |
# 何がしたかったか | |
- 過剰な例を試して初期値の渡り方を確認したかった | |
- Object内の初期値と引数自体の初期値を2種類宣言できてしまうところが毒にも薬にも成りうる | |
- 引数自体の初期値に入れたプロパティは、Object内のプロパティ以外採用されない | |
- DIコンテナ風の機構を作れないかと考えている | |
- この用途だと、[Decorators構文](http://qiita.com/armorik83/items/e3a0ce67f569ddc4b432)の方が便利かもと思い始めている | |
ご利用は計画的に。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment