2017-02-25 73 views
0

我對這種閉包行爲感到困惑。我讀過幾篇SO文章(包括this one)和MDN關於閉包的文檔,但沒有看到這種行爲的解釋。返回閉包的變量是創建一個副本而不是參考

在下面的代碼示例中,我創建了一個閉包,其中包含變量cache,修改該變量的函數preload以及記錄其值的函數report。它也重視引用那些對象傳遞進來。

'use strict'; 

var o = {}; 

(function(obj) { 
    var cache = {'initialized': false}; 

    function preload(assets, done) { 
     console.log('Preloading. Value of cache is', cache); 
     cache = {}; 

     for (var i = 0; i < assets.length; i++) { 
      cache[assets[i]] = assets[i]; 
     } 
    } 

    function report() { 
     console.log('Cache from inside is ', cache); 
    } 

    function get_cache() { 
     return cache; 
    } 

    obj.cache = cache; 
    obj.preload = preload; 
    obj.report = report; 
})(o); 

// {initialized: false}, as expected 
o.report(); 

// {initialized: false}, as expected 
console.log('Cache from outside is ', o.cache); 

// I expect this to change cache to {1:1, 2:2, 3:3} 
o.preload([1, 2, 3]); 

// {1:1, 2:2, 3:3}, as expected 
o.report(); 

// {initialized: false}, NOT as expected. Why? 
console.log('Cache from outside is ', o.cache); 

我的期望是根據我的理解是,當封閉重視cache所提供的obj,它被分配閉包內的變量的引用。但是我看到的行爲暗示obj.cache正在收到關閉cache副本

在哪一點上創建了cache的副本,爲什麼?

+0

爲什麼你不公開'get_cache'而是'cache'變量的初始值? – Bergi

+1

因爲你正在製作副本:'cache = {}'。請注意,唯一的閉包是變量'cache'本身。變量'obj.cache'不是一個閉包,而是像C或Java或其他語言中的常規引用/指針賦值。因此,它使'obj.cache'指向由'cache'指向的同一對象,而不是變量'cache'本身。換句話說,'obj.cache = cache'通過值將指針分配給緩存(它像大多數編程語言中一樣指針的拷貝) – slebetman

回答

2

當你在一開始叫obj.cache = cache;,你這是obj.cache指向cache指向(此對象:{'initialized': false})相同的對象

再後來,當你調用preload,你點的變量cache到另一個,新對象:cache = {};。現在cache變量指向一個全新的對象,而obj.cache仍指向一開始創建的舊對象。

這就解釋了爲什麼在閉包內的cache上完成的所有記錄記錄了新值,而記錄obj.cache仍顯示不變的值。他們現在指向2個不同的對象,並且更改cache現在指向的對象的內容對obj.cache指向的原始對象沒有任何影響。

+0

哦!咄!我甚至沒有想過'cache = {}'是將緩存重新分配給一個新的對象,但現在你指出它非常清楚。我認爲這只是清空「cache」引用的對象。這現在非常有意義,我的理智恢復了。謝謝。 – Mark

0

當您的IIFE執行時,您已將cache添加到obj.cache,就是這樣。 obj.cache不支持從您的IIFE引用cache變量。但是,reportpreload函數正在使用cache變量從您的IIFE,即使它們被調用超出它們已創建的範圍。因此,您的IIFE內部的範圍參考obj.preloadobj.report函數(這是觀察閉合的地方)的保留,但不適用於obj.cache

有關各種情況下如何觀察和行使封閉的更多細節,請查看此link

相關問題