JavaScriptにおけるオブジェクトと関数のある事柄[JavaScript言語の粋-N 1]
16076 ワード
今日「JavaScript言語の粋」を読んだとき、関数の一部について、ずっと理解しにくいと思っていました.コードは以下の通りです.
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
コードの最後の黄色のカッコに注意してください.本には「objに関数を割り当てていません.関数を呼び出した後に返された結果を割り当てています.この関数は2つの側面を含むオブジェクトを返し、value変数にアクセスする特権を引き続き享受しています」と書かれています.実はこのようなコードは、使うことも多いのですが、よく考えたことがありません.最後のカッコを外したら、関数(オブジェクト)を返します.
コードで上記のobjをこのように呼び出すと、typeof objを実行して結果を「object」として返すことができます.たとえば、次のようになります.
最後のカッコのペアを削除してtypeof objを実行して結果を「function」に戻す場合は、このオブジェクトを使用するには、初期化を宣言する方法を使用する必要があります.たとえば、次のようにします.
このように括弧の違いがあるかどうか理解しているようです.しかし、著者が後に挙げたFibonacciの例は、このような良い用途があるのかと悟った.すなわち、関数は、以前の操作結果をあるオブジェクトに記録し、無駄な繰り返し演算を回避することができる.
我々は通常の再帰方式によって、以下のようにFibonacci数値を計算する.
2回連続して実行すると、次のような結果が得られます.
はい、2回とも453回実行されました.毎回0、1から計算を再開しなければならないからです.
ただし、次のコードを使用している場合は(最後のカッコに注意してください):
2回連続して実行した結果、
はい、1回目は29回計算を行い、2回目は11回計算を行いました.なぜならmenoという配列に結果を保存したからです.
もちろん、グローバル変数のような他の方法で結果を保存することもできますが、グローバル変数は著者が極力反対している応用と記憶モードの一つであり、この計算結果の保存は、もともと対外的に透明であり、それを呼び出す人が必要とするのは計算結果だけで、どのように保存するかを知る必要はありません.あるいは私たちはこの計算関数以外の他の(グローバル)変数を必要としないか、あるいは後でこのコードを維持する人は、他の知らないところに知られる必要はありません.計算の中間結果があれば、彼が余分なメンテナンス作業をする必要があります.
もちろん、400回以上の計算を省く必要はありません.プログラムの効率に関心を持つ必要はありません.あるいは、ユーザーのブラウザがどれだけ遅いかを心配する必要はありません.
実は今までも通じていないで、それらの间の用途の区别あるいは优劣はどこにあって、ずっとこの事を言うPointがどこにあることを理解していないため、だから、博文のタイトルはいつもはっきり言っていないと感じます!皆さんのご指導をお願いします.
1: var obj = (function(){
2: var value = 0;
3:
4: return {
5: increment:function(inc){
6: value += typeof inc == "number"?inc:1;
7: },
8: getValue:function(){
9: return value;
10: }
11: };
12: }());
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
コードの最後の黄色のカッコに注意してください.本には「objに関数を割り当てていません.関数を呼び出した後に返された結果を割り当てています.この関数は2つの側面を含むオブジェクトを返し、value変数にアクセスする特権を引き続き享受しています」と書かれています.実はこのようなコードは、使うことも多いのですが、よく考えたことがありません.最後のカッコを外したら、関数(オブジェクト)を返します.
コードで上記のobjをこのように呼び出すと、typeof objを実行して結果を「object」として返すことができます.たとえば、次のようになります.
1: obj.increment(1);
2: alert(obj.getValue());//1
3: obj.increment(2);
4: alert(obj.getValue());//3
最後のカッコのペアを削除してtypeof objを実行して結果を「function」に戻す場合は、このオブジェクトを使用するには、初期化を宣言する方法を使用する必要があります.たとえば、次のようにします.
1: var o = obj();
2: o.increment(1);
3: alert(o.getValue());//1
4: o.increment(2);
5: alert(o.getValue());//3
このように括弧の違いがあるかどうか理解しているようです.しかし、著者が後に挙げたFibonacciの例は、このような良い用途があるのかと悟った.すなわち、関数は、以前の操作結果をあるオブジェクトに記録し、無駄な繰り返し演算を回避することができる.
我々は通常の再帰方式によって、以下のようにFibonacci数値を計算する.
1: var totalTimes = 0;
2:
3: var fibonacci = function (n){
4: totalTimes +=1;
5: return n<2?n:fibonacci(n-1) + fibonacci(n-2);
6: }
7:
8: function calculateFibonacci(){
9: totalTimes = 0;
10: for(var i =0;i<11;i++){
11: document.getElementById("rlt").innerHTML +="//"+i+":"+fibonacci(i)+"<br/>";
12: }
13: document.getElementById("rlt").innerHTML+="//totalTimes:"+totalTimes+"<br/>";
14: }
2回連続して実行すると、次のような結果が得られます.
1: //0:0
2: //1:1
3: //2:1
4: //3:2
5: //4:3
6: //5:5
7: //6:8
8: //7:13
9: //8:21
10: //9:34
11: //10:55
12: //totalTimes:453
13: //0:0
14: //1:1
15: //2:1
16: //3:2
17: //4:3
18: //5:5
19: //6:8
20: //7:13
21: //8:21
22: //9:34
23: //10:55
24: //totalTimes:453
はい、2回とも453回実行されました.毎回0、1から計算を再開しなければならないからです.
ただし、次のコードを使用している場合は(最後のカッコに注意してください):
1: var totalTimes = 0;
2: var fibonacciMemo = function(){
3: var meno = [0,1];
4: var fib = function(n){
5: totalTimes +=1;
6: var result = meno[n];
7: if(typeof result != "number"){
8: result = fib(n-1) + fib(n-2);
9: meno[n] = result;
10: }
11: return result;
12:
13: };
14: return fib;
15: }();
16:
17: function calculateFibonacciEx()
18: {
19: totalTimes = 0;
20: for(var i =0;i<11;i++){
21: document.getElementById("rlt").innerHTML +="//"+i+":"+fibonacciMemo(i)+"<br/>";
22: }
23: document.getElementById("rlt").innerHTML+="//totalTimes:"+totalTimes+"<br/>";
24: }
2回連続して実行した結果、
1: //0:0
2: //1:1
3: //2:1
4: //3:2
5: //4:3
6: //5:5
7: //6:8
8: //7:13
9: //8:21
10: //9:34
11: //10:55
12: //totalTimes:29
13: //0:0
14: //1:1
15: //2:1
16: //3:2
17: //4:3
18: //5:5
19: //6:8
20: //7:13
21: //8:21
22: //9:34
23: //10:55
24: //totalTimes:11
はい、1回目は29回計算を行い、2回目は11回計算を行いました.なぜならmenoという配列に結果を保存したからです.
もちろん、グローバル変数のような他の方法で結果を保存することもできますが、グローバル変数は著者が極力反対している応用と記憶モードの一つであり、この計算結果の保存は、もともと対外的に透明であり、それを呼び出す人が必要とするのは計算結果だけで、どのように保存するかを知る必要はありません.あるいは私たちはこの計算関数以外の他の(グローバル)変数を必要としないか、あるいは後でこのコードを維持する人は、他の知らないところに知られる必要はありません.計算の中間結果があれば、彼が余分なメンテナンス作業をする必要があります.
もちろん、400回以上の計算を省く必要はありません.プログラムの効率に関心を持つ必要はありません.あるいは、ユーザーのブラウザがどれだけ遅いかを心配する必要はありません.
実は今までも通じていないで、それらの间の用途の区别あるいは优劣はどこにあって、ずっとこの事を言うPointがどこにあることを理解していないため、だから、博文のタイトルはいつもはっきり言っていないと感じます!皆さんのご指導をお願いします.