2016-12-05 3 views
0

私はMozilla開発者サイトのクロージャの説明を読んでいて、少し苦労しています。 MozillaのWebサイトから次のコードを見てください。私はそれがどのように機能するのか理解していますが、コメントの下のコードも機能するはずです。 18と20をクリックするとなぜ機能しないのですか?JavaScript - クロージャ

/* mozilla dev code */ 
function makeSizer(size) { 
    return function() { 
     document.body.style.fontSize = size + 'px'; 
    }; 
} 

var size12 = makeSizer(12); 
var size14 = makeSizer(14); 
var size16 = makeSizer(16); 

document.getElementById('size-12').onclick = size12; 
document.getElementById('size-14').onclick = size14; 
document.getElementById('size-16').onclick = size16; 
/* end of mozilla dev example */ 
/* my code starts */ 
/* see - no inner function below */ 

function makeS(size) { 
     document.body.style.fontSize = size + 'px' 
} 
/* Let's see if that works */ 

var size18 = makeS(18); 
document.getElementById('size-18').onclick = size18; 



/* What about that? */ 

document.getElementById('size-20').onclick = makeS(20); 

なぜ

CodePen: http://codepen.io/wasteland/pen/qqoooW

+0

JavaScriptのクロージャはどのように機能しますか?(http://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – s3raph86

答えて

6

makeS(18)はすぐに機能を呼び出して、サイズを変更します。その場合にonclickイベントに割り当てる内容は、実際にはundefinedです。これは、呼び出されたときに関数が返すものです。明示的な戻り値がないためです。これとは対照的に

function makeS(size) { 
 
     document.body.style.fontSize = size + 'px' 
 
} 
 

 
console.log("font size before calling makeS:", document.body.style.fontSize); //it's actually an empty string, hence why it doesn't show up in the output 
 

 
var size18 = makeS(18); 
 

 
console.log("font size after calling makeS:", document.body.style.fontSize); 
 

 
console.log("what is size18?", typeof size18);

makeSizer(18)呼び出されたときに、サイズを変更することが、新たな機能を作成します。

function makeSizer(size) { 
 
    return function() { 
 
     document.body.style.fontSize = size + 'px'; 
 
    }; 
 
} 
 

 
console.log("font size before calling makeSizer:", document.body.style.fontSize); //it's actually an empty string, hence why it doesn't show up in the output 
 

 
var size18Function = makeSizer(18); 
 

 
console.log("font size after calling makeSizer:", document.body.style.fontSize); //it's still an empty string 
 

 
console.log("what is size18Function?", typeof size18Function); 
 

 
//let's call it now 
 
size18Function(); 
 

 
console.log("font size after calling size18Function:", document.body.style.fontSize); //it's now changed

0

18のあなたの呼び出しますのにOnclick。それは、size18あなたはそれがclousre変更可能(を介して動作したい場合は、siz18が)、ここでは未定義ことになるには何も返さない

チェックこのスニペットmakeSizerと同様の方法を返すように

function makeSizer(size) { 
 
    return function() { 
 
    document.body.style.fontSize = size + 'px'; 
 
    }; 
 
} 
 

 
var size12 = makeSizer(12); 
 
var size14 = makeSizer(14); 
 
var size16 = makeSizer(16); 
 

 
document.getElementById('size-12').onclick = size12; 
 
document.getElementById('size-14').onclick = size14; 
 
document.getElementById('size-16').onclick = size16; 
 

 

 
function makeS(size) { 
 
    return function() { 
 
    document.body.style.fontSize = size + 'px'; 
 
    } 
 
} 
 

 
/* Let's see if that works */ 
 

 
var size18 = makeS(18); 
 
document.getElementById('size-18').onclick = size18; 
 

 

 
/* What about that? */ 
 

 
document.getElementById('size-20').onclick = makeS(20);
body { 
 
    font-family: Helvetica, Arial, sans-serif; 
 
    font-size: 12px; 
 
} 
 
h1 { 
 
    font-size: 1.5em; 
 
} 
 
h2 { 
 
    font-size: 1.2em; 
 
}
<h1>How closures work</h1> 
 
<a href="#" id="size-12">12</a> 
 
<a href="#" id="size-14">14</a> 
 
<a href="#" id="size-16">16</a> 
 

 
<div> 
 
    <a href="#" id="size-18">18</a> 
 
    <a href="#" id="size-20">20</a> 
 
</div>

希望これは

4

閉鎖に役立ちますが、それが定義されているときに関数でスコープチェーンの変数を「覚える」の事実です。関数の引数は、実行時にちょうどローカル変数であるので、この:

function makeSizer(size) { 
    return function() { 
     document.body.style.fontSize = size + 'px'; 
    }; 
} 

は同等です:

上記の場合
function makeSizer() { 
    var size = 1; // or some other value 
    return function() { 
     document.body.style.fontSize = size + 'px'; 
    }; 
} 

、戻り値である匿名関数は、「覚えています'の値がsizeとなり、呼び出されるたびに使用されます。

MakeSizerは、ローカル変数sizeに異なる値を提供する 'ファクトリ'関数として扱う必要があります。

「ファクトリ」ファンクション内のファンクション定義ステートメントを使用せずに、このような「記憶」を達成することはできません。

0

クロージャとは、レキシカルスコープ内の変数へのアクセスを保持する関数の概念であり、渡されても宣言され、プログラム全体でさまざまな場所やスコープで呼び出されます。

Huh?

これはどういう意味ですか?たびfunctionFactoryコード

function functionFactory() { 
    var x = 1; 
    return function() { 
     return ++x; 
    }; 
} 

var first = functionFactory(); 
var second = functionFactory(); 

console.log(first()); // outputs 1 
console.log(first()); // outputs 2 
console.log(first()); // outputs 3 

console.log(second()); // outputs 1 

の下の部分を考えてみましょうが呼び出され、それはプライベート変数xを宣言し、その変数を変異させる匿名関数を返します。出力では、返された関数の後続の呼び出しであるfirstが異なる値を返すことがわかります。

secondを呼び出すと、1が返されます。なぜですか?それはfunctionFactoryという別々の呼び出しによって作成されたので、x以上の独自のクロージャに関する独自の参照があります。

なぜ気にしますか?

これは非常に便利な機能です。ファーストクラスの変数として関数を扱うプログラミング言語(javascriptなどの他の関数型言語も同様)では、私用変数のカプセル化のためにクロージャを使うことができます。代わりに、あなたのmakeS関数の出力を割り当てている、 - onclickは、あなたがそれに機能を割り当てることを期待ので、だからあなたの実際の質問に

...

あなたのコードが動作しない理由は、ありますvoidです。 makeSizerは、パラメータとして渡される数値の値を超えてクロージャを確立し、各要素のonclick変数に代入される関数を返しています。

これにより、物事がより明確になりますようお願いいたします。

関連する問題