1. takeharu

    No comment

    takeharu
Changes in body
Source | HTML | Preview
@@ -1,191 +1,191 @@
#Functional JavaScript(関数型言語としてのJavascript)
Javascriptでは関数型言語の一部の機能が備わっています。
ここでは小難しい話は抜きにして、より可読性やメンテナンス性などをよくするために、
実践的なJavascriptの関数型について考えていきます。
#関数型の特徴
実装のみを知りたい場合は、
この項を飛ばして、`気をつけるべきは三点`へどうぞ。
関数型の特徴としては
- 変数は再代入禁止である
- 関数は参照透過性が保たれている(副作用がない)
が挙げられます。
しかし、前者の`変数の再代入禁止`は縛りとして強すぎるので、
実践においてはそこまで重視しません。
ただ再代入が少ない程、可読性はあがると思います。
後者の`参照透過性`とは、
「引数が同じであれば何回その関数を実行しても結果が変わらない」ことをいいます。
後者の参照透過性を気をつける事により、
よりよい実装が目指せます。
キーワード
- 第一級関数(高階関数が扱える)
- カリー化(部分適用)
- 型推論
#気をつけるべきは三点
Javascriptで関数型を考えるにあたっては、
ポイントは下記三点となります。
- すべての関数が値を返す
-- 関数に副作用がない
-- 関数を値として扱える
+- 関数に副作用がない(参照透過)
+- 関数を値として扱える(高階関数)
関数型として気をつけるにはほかにもあるのですが、
今回は扱いません。
#すべての関数が値を返す
関数がすべての値を返すようにします。
```javascript
// Good
function hello() {
return 'Hello'
}
console.log(hello()); // Hello
// Bad
function hello() {
console.log('Hello');
}
hello();// Hello
```
-# 関数に副作用がない
+# 関数に副作用がない(参照透過)
簡単に考えると、下記2点となります
- 関数は外側の変数を変更しない
- 参照渡しの引数の値を変更しない
関数は外側の変数を変更しないの例です。
そもそも外側の変数は変更しないだけでなく、極力利用しないほうがいいです。
```javascript
// Good 副作用がない
var z = 2;
function add(x, y) {
return x + y;
}
console.log(add(z, 3)); // 5
console.log(add(z, 3)); // 5
// Bad 副作用がある
var z = 2;
function add(x, y) {
z = x + y;
return z;
}
console.log(add(z, 3)) // 5
console.log(add(z, 3)) // 8
```
次に参照渡しの引数の値を変更しないの例です。
```javascript
// Good 副作用がない
var arr = [1, 2, 3];
function double(arr) {
var _arr = [];
for(var i = 0; i < arr.length; i++) {
_arr.push(arr[i] * 2);
}
return _arr;
}
console.log(double(arr)); // [2, 4, 6]
console.log(double(arr)); // [2, 4, 6]
// Bad 副作用がある
var arr = [1, 2, 3];
function double(arr) {
for(var i = 0; i < arr.length; i++) {
arr[i] = arr[i] * 2;
}
return arr;
}
console.log(double(arr)); // [2, 4, 6]
console.log(double(arr)); // [4, 8, 12]
```
Goodでは、新しく配列を作りそこに一つずつ二倍した値をいれていっています。
しかし、Badでは二倍した要素を再び参照渡しで送られてきた配列にいれてしまっています。
それでは、外側の値に変更が生じてしまいます。
あえて二つに分けたのですが、
本当は一つ目の「関数は外側の変数を変更しない」で集約されますね。
-#関数が値として扱える
+#関数が値として扱える(高階関数)
関数が値として扱えるので引数に関数を渡して処理を委譲、
もしくは、関数を返り値として処理を委譲する事もできます。
```javascript
function calc(cal) {
return cal(3, 2);
}
function add(x, y) {
return x + y;
}
console.log(calc(add)); // 5
function sub(x, y) {
return x - y;
}
console.log(calc(sub)); // 1
```
足し算のaddや引き算のsubをcalc関数に渡して、
処理を委譲しています。
次にクロージャによる返り値として関数を返す例です。
```javascript
function human() {
var name = 'Haru39';
return function() {
return name;
}
}
var sayName = human();
console.log(sayName()); // Haru39
```
関数を返り値として処理を委譲しています。
さらにクロージャにより、カプセル化が実現できます。
クロージャがわからない方はこちらの記事へどうぞ。
[JavaScriptでクロージャ入門 ](http://qiita.com/Haru39/items/4975031faf6f7baf077a)
#まとめ
ポイントは三点。
- すべての関数が値を返す
- 関数に副作用がない
- 関数を値として扱える
注意点として、純粋関数型言語のように再代入ができないなどを考えると、
非常に非効率的な実装となってしまいます。
ループがfor文ではなく再帰を使用したりなど。
しかし、for文をラップして使用する事は非常にメリットがあります。
そういった関数型を支援するライブラリとして、underscoreがあります。
今度はそのunderscoreを使用した記事も書いていきます。
(さらに実務的なライブラリ、lodashとの比較も含め)
さらにカリー化などを用いて、関数でプログラムを組んでいくこともある程度は可能です。
カリー化もまた別の機会で紹介します。