JavaScript の関数に関するあれこれ

JavaScript シリーズの最後は、JavaScript の関数に関するまとめ。自分の知らないことを中心にいくつかサンプルを書いて見ます。

# 関数の順番

JavaScript では、関数の定義は、関数を使用する前でも、後でも構いません。実行される時に、関数は全て前に持ってこられます。

# arguments

JavaScript には予約されている`arguments` というプロパティがあります。それを使うと、可変のプロパティも扱えます。

```js
function printArgs() {
    for (i = 0; i < arguments.length; i++) {
        console.log(arguments[i])
    }
}
x = printArgs(1, true, "Hello")
```

実行結果

```
1
true
Hello
```

# 関数の引数

関数の引数には、値渡しと、参照渡しがあります。プリミティブ型は値渡しで、オブジェクトだと参照渡しとのことです。下記の例では、statement は、文字列型、empはオブジェクトです。
`changeValues` 内で、パラメータに対して新しい値をアサインしていますが、実際に反映されるのは、オブジェクト (emp) のみです。

```js
function changeValues(statement, emp) {
    statement = "Hi, guys";
    emp.name = "Taro";
}

var statement = "Hello guys";
var emp = new Employee("Yamada");

console.log(statement);
console.log(emp.name);
changeValues(statement, emp);
console.log(statement);
console.log(emp.name);
```

実行結果

```
Hello guys
Yamada
Hello guys
Taro
```

# call

メソッドを呼び出す方法はいくつかありますが、その一つが、`call` を使う方法です。call を使うと、他のオブジェクトに属するメソッドを使えます。下記の例では、`emp` のメソッドを、`myEmp` の属性に対して実行しています。

```js
var emp = {
    name: "Tsuyoshi",
    baseSalary: 100,
    salary: function() {
        return this.baseSalary * 2 + 1;
    }
}

var myEmp = {
    name: "Takeru",
    baseSalary: 200
}

console.log(emp.name);
console.log(emp.salary());
console.log(emp.salary.call(myEmp));
```

```
Tsuyoshi
201
401
```

# apply

call とほぼ同じですが、引数を配列で扱えます。

```js
console.log(Math.max.apply(null, [4,6,90]))
console.log(Math.max.call(null, 39,20,1))
```

```
90
39
```

# self invoke method

関数は通常定義するだけでは、実行されませんが、定義して、即実行したい時に使います。

```js
var value = "default";

// self invoke method

(function () {
    value = "hello!";
})();

console.log(value);
```

`(function() {...})();` とすることにより、その場で関数が実行されるので、`value` の値が書き換えられます。実行結果はこちら。

```
hello!
```

# closure 

クロージャを使うと、関数に、通常 JavaScript ではできない、プライベートのプロパティや、関数を持つことができます。ポイントは、戻り値として関数を返しているところです。素直に考えると、関数を返した時点では、演算は行われず、関数を実行した時点での、`counter` が参照されそうです。ところが、クロージャでは、この関数が戻された時の、状態を保持したまま返されます。

だから、次のようなコードを書くと、`add1` `add2` それぞれで、値がインクリメントされます。

```js
var add1 = (function () {
    var counter = 0;
    return function() {return counter += 1;}
})();

var add2 = (function () {
    var counter = 0;
    return function() {return counter += 1;}
})();

console.log(add1());
console.log(add1());
console.log(add2());
console.log(add2());
```

実行結果

```
1
2
1
2
```

## 通常の関数と、クロージャの違い

通常の関数と比べると、クロージャは関数を返しています。通常の関数だと、毎回`count`が初期化されるため、値を保持できません。

```js
unction execFunc() {
    var count = 0;
    function add() {
        count++;
    }
    function display() {
        console.log(count);
    }
    add();
    display();
}

execFunc();
execFunc();

function execClosure() {
    var count = 0;
    return {
        add: function() {
            count++;
        },
        display: function() {
            console.log(count);
        }
    }
};

var closure = execClosure();
closure.add();
closure.display();
closure.add();
closure.display();

```
実行結果

```
1
1
1
2
```



## Private の実現

この仕組みを利用して、プライベート属性を実現することができます。クロージャが戻されると、元々の関数の方には、クロージャからアクセスできますが、直接はアクセスできません。

```js

var count = (function() {
    var counter = 0;
    function modify(num) {
        counter += num;
    }

    return {
        add: function() {
            modify(1);
        },
        remove: function() {
            modify(-1);
        },
        get: function() {
            return counter;
        }
    };
})();

console.log(count.get());
count.add();
count.add();
console.log(count.get());
count.remove();
console.log(count.get());

count.modify(1); // error
```

実行結果

```
0
2
1

 count.modify(1); // error
       ^

TypeError: count.modify is not a function
```

# クロージャとクラス

ちなみに、状態を持てるということは、クラスと何が違うの？と思ってしまいます。

クロージャとクラスを比較すると、クロージャーの方がメモリをよく食う（メソッドが毎回インスタンス化されるので）しかし、テスタビリティは優れているという話もあります。（まだ調べていません。メモ程度）。となると、後のメリットである、Private を作れるという話ですが、ここまでやって、private を作るべきか？というと微妙かもと思います。効率を考えると基本クラスで問題なさげですが、クロージャの良いユースケースがあったらぜひ教えてください。

次のリソースの中には、DI を使っているときはクロージャはしやすいという記事がありました。ちなみに、使っていないときは、Class の方がモックが楽で、Clousure を使っているとできるけどダークマジックが必要とあります。clousure は liablity (責任を持つこと）に有利で、class はメモリ効率で有利とあります。

# リソース

* [Function Closures](https://www.w3schools.com/js/js_function_closures.asp)
* [クラスの落とし穴2 - メソッドとクロージャ](http://qiita.com/cocottejs/items/0c1756ac7e7ec8bae7cb)
* [Classes vs. Closures - Performance](https://www.reddit.com/r/javascript/comments/6enbvb/classes_vs_closures_performance/)
* [Javascript Classes vs. Closures (3/3) Testability](https://medium.com/engineering-livestream/javascript-classes-vs-closures-3-3-9d9233eb0a5c)