回答編集履歴
3
誤ったコメントを削除
answer
CHANGED
@@ -49,7 +49,7 @@
|
|
49
49
|
|
50
50
|
if (Object.prototype.toString.call(arg) === '[object Array]') { // 2. If the value of the [[Class]] internal property of arg is "Array", then return true.
|
51
51
|
|
52
|
-
return true;
|
52
|
+
return true;
|
53
53
|
}
|
54
54
|
|
55
55
|
return false; // 3. Return false.
|
2
typo修正、参照透過性が成り立つコードの説明を修正
answer
CHANGED
@@ -22,7 +22,7 @@
|
|
22
22
|
この原則の利点として、アルゴリズムを書きだした時に**すっきりした構造となること**が挙げられます。
|
23
23
|
入口/出口が複数あると、考えるパターンが複雑化してしまい、人間の目で見て追いきれない事があります。
|
24
24
|
|
25
|
-
しかしながら、構造化プログラミングには入口/出口が狭い都合上、コードの階層が深くなってしまう欠点があり、最近の考え方としては「例外処理は先に返
|
25
|
+
しかしながら、構造化プログラミングには入口/出口が狭い都合上、コードの階層が深くなってしまう欠点があり、最近の考え方としては「例外処理は値を先に返す事で追い出してしまい、後続コードを正常系処理のみにする事ですっきりしたアルゴリズムにしよう」が主流なようです。
|
26
26
|
実際にJavaScriptの基本仕様である ECMAScript でも同様のアルゴリズムが組まれています。
|
27
27
|
一例として、ECMAScript 5.1 規定の `Array.isArray` の処理を読んでみましょう。
|
28
28
|
|
@@ -59,7 +59,7 @@
|
|
59
59
|
|
60
60
|
このコードは「入口が一つ、出口は複数」ですが、正常系処理に限っては「入口が一つ、出口が一つ」とする事で構造化プログラミングの理念の則ってすっきりしたコードを書けます。
|
61
61
|
|
62
|
-
余談ですが、入口
|
62
|
+
余談ですが、入口を一つにする原則は、「**参照透過性が成り立つコード**」を組む時にも通用する考え方となります。
|
63
63
|
参照透過性が成り立たないコードは「引数とは別に入口がある」と考えられるからです。
|
64
64
|
|
65
65
|
### 複数の出口を持つコード
|
1
「構造化プログラミング」の節を追記。それに伴い、「複数の出口を持つコード」の節に補足説明を追記。
answer
CHANGED
@@ -1,8 +1,73 @@
|
|
1
|
+
### 構造化プログラミング(structured programming)
|
2
|
+
|
3
|
+
構造化プログラミング(structured programming)と呼ばれる思想があり、その原則に「**関数は単一の入口と単一の出口を持つべきである**」というものがあります。
|
4
|
+
|
5
|
+
```JavaScript
|
6
|
+
'use strict';
|
7
|
+
function getHeightClamped (text) { // 仮引数 (単一の入口)
|
8
|
+
const minHeight = 5;
|
9
|
+
const maxHeight = 10;
|
10
|
+
const textHeight = text.split("\n").length; // 返り値となる変数を作る
|
11
|
+
|
12
|
+
if (textHeight < minHeight) {
|
13
|
+
textHeight = minHeight; // 返り値に最小値を代入する
|
14
|
+
} else if (textHeight > maxHeight) {
|
15
|
+
textHeight = maxHeight; // 返り値に最大値を代入する
|
16
|
+
}
|
17
|
+
|
18
|
+
return textHeight; // 返り値を返す (return 節を一度だけ使う事で単一の出口となる)
|
19
|
+
}
|
20
|
+
```
|
21
|
+
|
22
|
+
この原則の利点として、アルゴリズムを書きだした時に**すっきりした構造となること**が挙げられます。
|
23
|
+
入口/出口が複数あると、考えるパターンが複雑化してしまい、人間の目で見て追いきれない事があります。
|
24
|
+
|
25
|
+
しかしながら、構造化プログラミングには入口/出口が狭い都合上、コードの階層が深くなってしまう欠点があり、最近の考え方としては「例外処理は先に返して追い出してしまい、後続コードを正常系処理のみにする事ですっきりしたアルゴリズムにしよう」が主流なようです。
|
26
|
+
実際にJavaScriptの基本仕様である ECMAScript でも同様のアルゴリズムが組まれています。
|
27
|
+
一例として、ECMAScript 5.1 規定の `Array.isArray` の処理を読んでみましょう。
|
28
|
+
|
29
|
+
- [15.4.3.2 Array.isArray ( arg ) - ECMA-262 Edition 5.1](http://ecma-international.org/ecma-262/5.1/#sec-15.4.3.2)
|
30
|
+
|
31
|
+
> 1. If Type(arg) is not Object, return false.
|
32
|
+
> 2. If the value of the [[Class]] internal property of arg is "Array", then return true.
|
33
|
+
> 3. Return false.
|
34
|
+
|
35
|
+
1. 引数 `arg` が Object 型でない場合は `false` を返す
|
36
|
+
2. 引数 `arg` の内部プロパティ `[[Class]]` が `"Array"` ならば、`true` を返す
|
37
|
+
3. `false` を返す
|
38
|
+
|
39
|
+
1., 2., 3. のstepで**「そうでなければ(else)」の文言がないのは、前stepで値を返す事で例外処理が終わっている為**です。
|
40
|
+
互換コード(Polyfillコード)は次のように書けます。
|
41
|
+
|
42
|
+
```JavaScript
|
43
|
+
Object.defineProperty(Array, 'isArray', {writable: true, enumerable: false, configurable: true,
|
44
|
+
value: function isArray (arg) { // 1. If Type(arg) is not Object, return false.
|
45
|
+
|
46
|
+
if (Object(arg) !== arg) {
|
47
|
+
return false;
|
48
|
+
}
|
49
|
+
|
50
|
+
if (Object.prototype.toString.call(arg) === '[object Array]') { // 2. If the value of the [[Class]] internal property of arg is "Array", then return true.
|
51
|
+
|
52
|
+
return true; // 3. Return false.
|
53
|
+
}
|
54
|
+
|
55
|
+
return false; // 3. Return false.
|
56
|
+
}
|
57
|
+
});
|
58
|
+
```
|
59
|
+
|
60
|
+
このコードは「入口が一つ、出口は複数」ですが、正常系処理に限っては「入口が一つ、出口が一つ」とする事で構造化プログラミングの理念の則ってすっきりしたコードを書けます。
|
61
|
+
|
62
|
+
余談ですが、入口と出口を制限する原則は、「**参照透過性が成り立つコード**」を組む時にも通用する考え方となります。
|
63
|
+
参照透過性が成り立たないコードは「引数とは別に入口がある」と考えられるからです。
|
64
|
+
|
65
|
+
### 複数の出口を持つコード
|
66
|
+
|
1
67
|
私は基本的に汎用性重視でコードを組みます。
|
2
68
|
|
3
69
|
- 最小値/最大値は引数で指定します(オプション)
|
4
70
|
- 引数無しは無制限です
|
5
|
-
- if -> return のコードは後続コードが実行されないので、else-if で繋ぎませんでした
|
6
71
|
|
7
72
|
```JavaScript
|
8
73
|
'use strict';
|
@@ -28,4 +93,11 @@
|
|
28
93
|
console.log(getHeightClamped('a\nb', 3)); // 3 (最小値: 2 / 最大値: 無制限)
|
29
94
|
```
|
30
95
|
|
96
|
+
`return` 節が複数存在する事から、このコードは「構造化プログラミング」の原則に反しています。
|
97
|
+
このコードは「例外処理系」と「正常処理系」を分割する事に利点があると考える為、else-if 節で繋がず、空行を開ける事で「それぞれの例外処理」を細かく分けるように書いています。
|
98
|
+
|
99
|
+
### 更新履歴
|
100
|
+
|
101
|
+
- 2017/10/29 16:37 「構造化プログラミング」の節を追記。それに伴い、「複数の出口を持つコード」の節に補足説明を追記。
|
102
|
+
|
31
103
|
Re: nabettu さん
|