LoginSignup
12
12

More than 5 years have passed since last update.

varよりletを使った方が良い

Posted at

と思いました。

たとえば、0から4までの整数を返す5つの関数を作成しようと思って次のようなコードを作成したとしましょう。これを実行すると、期待に反して、arrayのそれぞれの要素を呼び出して得られる値は全て5となります。

function F() {
... var array = [];
... for (var i = 0; i < 5; i++) {
..... array[i] = function () {
....... return i;
....... };
..... }
... return array;
... }
undefined
> var array = F();
undefined
> array[0]();
5
> array[1]();
5
> array[2]();
5
> array[3]();
5
> array[4]();
5

これ自体はJavaScript以外の言語でもやってしまいがちな間違いです。修正しましょう。

> function F() {
... var array = [];
... for (var i = 0; i < 5; i++) {
..... var j = i;
..... array[j] = function () {
....... return j;
....... };
..... }
... return array;
... }
undefined
> var array = F();
undefined
> array[0]();
4
> array[1]();
4
> array[2]();
4
> array[3]();
4
> array[4]();
4

JavaScript以外の普通の言語の感覚で修正しましたが、これでも上手く行きません。C#などならこれで上手く行くはずなのですが。

これは、JavaScriptの場合、変数の有効範囲は関数単位だからです。上のコードの場合、変数jの有効範囲は関数Fの全域です。ブロック単位の有効範囲というものはvarで宣言された変数にはなく、5回のループの中で使われている変数jは全て同じ変数です。

このような場合にはletで変数を宣言しなければなりません。letで宣言された変数はブロック単位の有効範囲を有します。

> function F() {
... var array = [];
... for (var i = 0; i < 5; i++) {
..... let j = i;
..... array[j] = function () {
....... return j;
....... };
..... }
... return array;
... }
undefined
> var array = F();
undefined
> array[0]();
0
> array[1]();
1
> array[2]();
2
> array[3]();
3
> array[4]();
4

ちなみに、letを使いたくない場合には、クロージャを使います。

> function F() {
... var array = [];
... for (var i = 0; i < 5; i++) {
..... array[i] = (function (x) {
....... return function () {
......... return x;
......... };
....... }(i));
..... }
... return array;
... }
undefined
> var array = F();
undefined
> array[0]();
0
> array[1]();
1
> array[2]();
2
> array[3]();
3
> array[4]();
4
12
12
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
12