2012-06-26 31 views
0

我看到這是一個example on MDN,並不明白爲什麼這是一個Good Thing(TM)。這是一個封閉的好例子嗎?

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

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

爲什麼上面比下面更好?

function makeSizer(size) { 
     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; 

<a href="#" id="size-12">12</a> 
<a href="#" id="size-14">14</a> 
<a href="#" id="size-16">16</a> 
+0

我必須承認這是一個措辭嚴厲的問題。深夜發佈將做到這一點:)我要問的是爲什麼我會使用閉包,而不是隻做'onclick = makeSizer(14);'? makeSizer(14)指的是函數的第二個版本。我會按照Kooilnc的建議去玩jsFiddle。 – dotnetN00b

回答

2

在這種情況下size是封閉的可變。調用makeSizer(12)將返回「記住」12的函數引用。此函數引用被分配給元素上的點擊處理程序(請參閱MDN示例中的其餘代碼)。它說:如果你點擊我,請致電(執行)size12。在點擊時,由於從makeSizer(12)返回的函數引用被執行(所包含的值爲12),所以正文的字體大小變爲'12px'。

如果您已經使用了該功能,您將立即調整字體大小。

function makeSizer(size) { 
     document.body.style.fontSize = size + 'px'; 
} 
var size12 = makeSizer(12); 
var size14 = makeSizer(14); 
var size16 = makeSizer(16); //=> now the font-size of the body is '16px' 

認爲當你做在這種情況下會發生什麼:

document.getElementById('size-12').onclick = size12; 

會發生什麼,如果你點擊#size-12

您鏈接到jsfiddle example的鏈接的MDN頁面。試試看!

不好是我樂意留給社會更宗教的部分。我會說這個封閉是有用的,甚至可能很方便。

+0

與此形成鮮明對比的是,只設置body的fontSize的makeSizer版本將返回未定義的值,而不是適合用作按鈕的onclick處理函數的函數。 – minopret

1

沒有一個更好,但他們的行爲有所不同。

第一不會實際大小,直到你調用返回的功能如下:

size12(); 

你的第二個例子中首先聲明一個函數,然後調用它的3倍。您立即將大小設置爲12px,然後14px,最後是16px。

0

您對「好」的標準是什麼?

在第一個示例中,您創建了一些函數,然後必須調用它才能完成該工作。尺寸保持封閉,很難看到任何好處。你可能想要做的:

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

var setSmall = makeSizer(8); 
var setMedium = makeSizer(10); 
var setLarge = makeSizer(14); 

或類似的,所以現在你只要致電:

setSmall(); 

在第二種情況下的功能應該被稱爲像的setSize

一個封閉的另一個用途是:

var setSize = (function() { 
    var sizes = {small: 8, medium: 10, large: 14}; 

    return function(size) { 

    if (sizes.hasOwnProperty(size)) { 
     document.body.style.fontSize = sizes[size] + 'px'; 
    } 
    } 
}()); 

setSize('small'); 

無論他們是「好」,「壞」或什麼取決於你的標準對他們進行分類如此。

0

在第一個例子中,makeSizer返回一個函數。在第二個示例中,它不返回任何內容,並且具有誤導性的名稱。兩者完全不同。

第一個例子中的推理是makeSizer是一個函數工廠;它使「sizer」功能。 size12,size14size16是特定的「sizer」功能,由makeSizer製作。如果其中一個稍後調用,它將設置字體大小。

在第二個示例中,首先將字體大小設置爲12,然後設置爲14,然後設置爲16,並在每個階段將無用的返回值保存到變量中。

0

其實,你在那裏有而不是封閉的例子。

維基百科告訴我們,closure的定義是一個「」函數以及該函數的非局部變量的引用環境。

更簡單地說,它是一個包圍周圍範圍變量的函數。

一個很好的例子是這樣的:

public Func<int> ClosureExample() 
{ 
    int a = 1, 
     b = 2; 

    Func<int> closeIt =() => a + b; 
    return closeIt; 
} 

讓我們好好看看這個是怎麼回事。我們聲明瞭兩個整數,然後使用lambda表達式/閉包/匿名方法(全部爲分配給第一類函數泛型的定義的有效名稱)返回將用於執行此計算的第一類函數,使用封閉變量,其他地方。

你可以說closeIt包含整數a和b;這些變量不屬於閉包,但它們正在被它使用。

+1

閉包**的MDN示例(在本例中爲第一個函數)是**閉包。所以我不瞭解你說的不是。 – dotnetN00b

+0

'public Func Foo() { int a = 1,b = 1; return()=> a == b? 「是!」 :「不......」; } public void Bar() { Func foo = Foo(); foo(); }' Foo方法返回一個lambda表達式,該表達式引用方法中的整數A和B;這些變量被說成是由方法「封閉」的。 酒吧叫Foo。包含這些變量的函數將返回並存儲在foo中。當foo被調用時,「是!」返回。 foo附上a和b;當Foo超出範圍時,那些應該是GC'd。然而,他們被擱置......至少在Bar()超出範圍之前。 –

+0

但參數'size'來自父函數makeSizer,匿名函數封裝'size'。不是嗎?無論參數是傳遞給父函數還是在父函數中聲明,但顯然在匿名函數之前,都無關緊要。在這兩種情況下,變量都在父範圍內。 – dotnetN00b