javascriptのクロージャが理解できずに苦しんでいます。
下記のようなコードをよく見るのですが、a()とfuncA()()が等価のようなのですが
実行するとa()の場合のみ変数の値が維持されます。
a()とfuncA()()の違いを理解したいと思っています。
どなたかどうぞよろしくお願い致します。
またクロージャのわかりやすい解説サイトなどご存知の方いらっしゃいましたら
合わせてよろしくお願い致します。
function funcA() {
var i = 10;
return function() {
i++;
alert(i);
};
};
var a = funcA();
console.log(a() === funcA()())//true
funcA()();//11
funcA()();//11
funcA()();//11
a();//11
a();//12
a();//13
No.2ベストアンサー
- 回答日時:
周知だと思いますが、
JavaScriptでは関数への参照にカッコ()を付けると関数を実行します。
var foo = function() { alert('a'); }; // fooは関数への参照
foo(); // 'a'と表示
次に質問文にあるような関数(クロージャ)を返す関数の場合です。
次に↓の文です。
var a = funcA();
funcAを実行して返ってくるのはクロージャへの参照です。
funcAの内部変数iが10にリセットされ、aにはクロージャへの参照が代入されます。
また、JavaScriptでは「全ての参照がなくなるまでオブジェクト(変数・関数を含む)は存在し続ける」ので、返されるクロージャとそこで使われている変数iは、funcAの外でもaがある限りは存在し続けます。
次に↓の文です。
funcA()();
「funcA()」はクロージャへの参照が返されるので、更にカッコを付けて「funcA()()」とすると返されたクロージャを実行することになります。
つまり、「funcAを実行して、返されたクロージャも実行する」という事を1文で済ませた表記です。
funcAを実行するため、iは10にリセットされ、クロージャの実行によってiは11になります。
次に↓の文です。
a();
これは返されたクロージャのみを実行しています。
funcA自体は実行しませんので、iはリセットされず、aを実行するたびにインクリメントしていきます。
参考URL:http://d.hatena.ne.jp/jdg/20091020/1256042918
ご回答ありがとうございます。
a()とfuncA()()の違いよく分かりました!
またクロージャについてもなんとなくわかってきたきがします。
どうもありがとうおございました。
No.7
- 回答日時:
「クロージャ」という用語に惑わされないで下さい。
ECMAScript 言語規定にこの用語は(ごく特殊な場面を除き)出てきません。JavaScript における変数の有効範囲が、結果的に「いわゆるクロージャっぽいもの」を形作るというだけで、特別な概念でも何でもありません。まず、JavaScript の変数は、基本的に「書かれている通りに、内から外へ」です。
var GlobalVar = 'Global';
function OuterFunc() {
var OuterVar = 'Outer';
function InnerFunc() {
var InnerVar = 'Inner';
alert(InnerVar); // 'Inner'
alert(OuterVar); // 'Outer'
alert(GlobalVar); // 'Global'
}
InnerFunc();
alert(InnerVar); // error!!!
alert(OuterVar); // 'Outer'
alert(GlobalVar); // 'Global'
}
OuterFunc();
alert(InnerVar); // error!!
alert(OuterVar); // error!!
alert(GlobalVar); // 'Global'
関数 InnerFunc 内からは InnerVar、OuterVar、GlobalVar の 3 つの変数を全て利用できます。しかし、関数 OuterFunc 内から変数 InnerVar は見えませんし、グローバルコンテキストからは GlobalVar しか見えません。外側の関数は内側の変数を使えないが、内側の関数は外側の変数も見える。当たり前ですね。
次に、JavaScript の関数は何でも戻り値にできます。
function F() {
return 1;
return [1, 2];
return {a:1, b:2};
}
たとえ、それが関数でも。
function OuterFunc() {
var OuterVar = 'Outer';
function InnerFunc() {
var InnerVar = 'Inner';
alert(InnerVar); // 'Inner'
alert(OuterVar); // 'Outer'
}
return InnerFunc;
}
var ifunc = OuterFunc();
ifunc();
関数 OuterFunc の戻り値 ifunc は、関数 InnerFunc そのものです。ゆえに、ifunc に丸括弧 () で引数を渡せば関数として呼び出すことができます。そして、関数 InnerFunc の定義は関数 OuterFunc の中にありますから、変数 OuterVar が見える。つまり、戻り値 ifunc(その実体は InnerFunc)を媒介にして、本来外側から利用できないはずの OuterVar を制御できてしまうわけです。
あと、実行コンテキストや初期化子など細かい事項はありますが、いちいち書きません。JavaScript のいわゆるクロージャは、JavaScript の変数スコープから生まれる結果の 1 つに過ぎません。ですから「こう書くのがクロージャ」と決めつけずに、いろいろ変数の管理方法を工夫していけば、そのうち慣れると思います。
あるいは、先に再帰に慣れて下さい。その方がいわゆるクロージャを理解しやすいと思います。
参考URL:http://web.archive.org/web/20061018193606/http:/ …
ご回答ありがとうございます。
無理に理解しようとせずにと思いつつもつい気になってしまいまして、、、。
とても参考になりました。ありがとうございました。
No.6
- 回答日時:
むだにかいとうがおおい#5です。
ていせい。
は、10をしょきちとする、かうんた製造機だ。返り血はない。
を
は、10をしょきちとする、かうんた表示機製造機だ。返り血はない。
に。
以下
かうんた製造機
を
かうんた表示機
に。
くるしんでいるところに、めんどうにさせて、きずぐちに塩をぬってやったみたい!ごめん。
No.5
- 回答日時:
なになに、ばぶばぶ。
function funcA() {
var i = 10;
return function() {
i++;
alert(i);
};
}
は、10をしょきちとする、かうんた製造機だ。返り血はない。
var a = funcA();
は、a を かうんた製造機にした。
a() === funcA()()
の a()は、
aを、かうんとしてみた。けっかはなにもない。(11をひょうじしただけ)
ないぶのかうんたは11となった
funcA()()は、
へんすうにだいにゅうしないで、かうんた製造機をつくったけど、すぐじっこうした。
だけど11をひょうじしただけで、けっかはなにもない
なにもないどうし、くらべたから、おんなじだった。
funcA()();
funcA()();
funcA()();
へんすうにだいにゅうしないで、かうんた製造機をつくったけど、すぐじっこうした。
だけど11をひょうじしただけで、けっかはなにもない。を3かいやってみた。
a();//11 <これって12からじゃない?
a();//12
a();//13
aのかうんたを3かいふやした。
ご回答ありがとうございます。
より理解を深めるため今後何度も読み返させていただきたいと思います。
どうもありがとうございました。
No.4
- 回答日時:
まずオブジェクトについて少し。
var obj = { pro: 1 };
objが持つ値は「参照」です。参照を値に持てば、それはオブジェクトです。
参照とはプロパティ集合のある場所(メモリ領域)を示すアドレスのようなものと考えていいと思います。
var variable = obj;
variableに代入されたのは「参照」です。(参照渡し)
variableはプロパティ集合(pro) へのアクセス手段を手に入れただけで、variable固有のプロパティが複製されるわけではありません。
pro(プロパティ)はobj固有のものではなく「参照固有のもの」と言えます。
これらを踏まえて
console.log(a() === funcA()())//true
ここで混乱してしまっているようですが
var a = funcA();
var v1 = a();
var v2 = funcA()();
alert(v1); // undefined
alert(v2); // undefined
どちらも戻り値が同じundefinedです。意図した比較ではないですよね。
alert(a === funcA()); // false
オブジェクト(参照)比較ならこのようになるかと。
funcA関数は関数式(function() { ... })から返されるFunctionオブジェクト(参照)を
戻り値(return)として返しますが、関数式はすでに変数aに代入され使用されているのと同じ参照を返すことはありません。
これはローカル変数(var宣言)も同じです。ローカル変数は関数呼出し時に初期化されます。
初期化の際、内側の関数式で使用(クロージャ)され解放されずにいるものと同じ参照が割り当てられることはありません。
funcA()()の場合、funcA関数から返されるFunctionオブジェクトを保持する対象はありません。関数実行後にクロージャ変数を含む参照先のメモリ領域は解放されます。
プロトタイプやクロージャを知らなくても、グローバルな変数や関数を並べるだけである程度のことはできます。
意欲的な姿勢は見習いたいですが、あまり先走り過ぎるのもどうかと。。。(苦しむのって面白い?)
*誤った解釈があればフォローお願いします。
ご回答ありがとうございました。
仰るとおり先走ってます。
a(),funcA()の違いよくわかりました。
より理解できるよう何度も読み返させていただきます。
どうもありがとうございました。
No.3
- 回答日時:
私はクロージャをそれほど理解しているわけではないのですが、要所要所に console.info() を入れるとわかりやすいんじゃないでしょうか。
function funcA() {
console.info('--- funcA');
var i = 10;
return function() {
console.info('closure');
i++;
console.log(i);
}
};
var a = funcA();
console.log(a() === funcA()());//true
console.log((funcA())() === funcA()());//true
funcA()(); //11
(funcA())(); // 11
a();//11
a();//12
a();//13
(funcA())(); は匿名関数とよく似ています。
(function(){ // 処理 })(); は function(){ // 処理 } を括弧で括ってオブジェクト化した上で実行するわけですが、
(funcA())(); は funcA() を実行した上でオブジェクト化し、内部のクロージャも実行しています。
No.1
- 回答日時:
わかりやすい解説サイト
http://www.atmarkit.co.jp/fdotnet/ajaxjs/ajaxjs0 …
とか
わかりにくい解説サイト(ECMA-262の邦訳)
http://www2u.biglobe.ne.jp/~oz-07ams/prog/ecma26 …
とか
var a = funcA();
は、funcA()の結果の代入ではなくて、funcA()をインスタンス化している。
別のアドレス空間にaの名前でfuncA(クラスオブジェクト)が確保されている。だからa()を呼ぶたびにクラス内のコードが実行され保持されている。だからa();//11 a();//12 a();//13
となる。
一方
funcA()();はfuncAを直接毎回実行するわけだから、常に
funcA()();//11
となる。
ちがっているかも。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- JavaScript javascript作成してます。ラジオボタンで判定するコードを書いてます。 1 2023/07/18 11:03
- JavaScript jQueryでのドラッグアンドドロップについて 1 2022/07/07 21:04
- JavaScript JAVASCRIPT 2 2022/04/15 15:10
- JavaScript スマフォではボタンを表示させたくない 2 2023/01/20 14:26
- JavaScript 変数のスコープの問題? 3 2022/06/23 09:32
- JavaScript コードレビューをお願いします。 1 2022/07/16 05:38
- JavaScript JavaScriptの即時関数の書き方 1 2022/11/29 09:52
- JavaScript 1日1回引けるJavaScriptおみくじについて 1 2022/12/12 22:28
- JavaScript 正規表現について質問です。条件に合う場合はtrueを返したい 3 2022/10/06 23:02
- JavaScript javascriptで変数を組み込みたい 2 2023/01/13 09:52
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
デザイン時のVisible=Falseは実...
-
PowerPointで時計表示
-
if(1){...}とはどういうことで...
-
jQuery ui Datepicker 明日以降...
-
VBA SORT Applyでエラー
-
VB.netでタイマーがスタートし...
-
初心者です。gulpでコンパイル...
-
JSPの処理の途中で、JavaScript...
-
VBA ステータスバー DoEvents
-
ラベルの色がかわってくれない
-
オーバーライドについて。
-
GoTo文とかSelect文の処理の仕...
-
JavaScriptでショートカットキ...
-
system関数を使用時にDos窓を最...
-
乱数の表示
-
CreateFile、CloseHandleの繰り...
-
VB.netの重複データ数カウント...
-
Excel VBA にて JavaScript の...
-
javascriptでsjisの文字列からu...
-
1つのVBAコードをすべてのコア...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
以下のコードを実行しても、オ...
-
JSPの処理の途中で、JavaScript...
-
if(1){...}とはどういうことで...
-
1つのVBAコードをすべてのコア...
-
VBA ステータスバー DoEvents
-
〔Excel:VBA〕マクロの実行が異...
-
jQuery ui Datepicker 明日以降...
-
デザイン時のVisible=Falseは実...
-
VBA SORT Applyでエラー
-
リクエスト結果が一瞬しか表示...
-
C#でボタン名を変更しても動く
-
PowerPointで時計表示
-
innerHTMLなどの反映タイミング
-
javascriptで最初のところに戻...
-
初心者です。gulpでコンパイル...
-
onbeforeunload と aタグの hre...
-
ラベルの色がかわってくれない
-
エクセル VBA タイマー動作 の...
-
JavaScriptで、実行するたび値...
-
Excel VBA にて JavaScript の...
おすすめ情報