Javascript 返回一个闭包';s变量正在创建副本而不是引用
我被这种闭包行为弄糊涂了。我已经阅读了好几篇SO文章(包括)和MDN关于闭包的文档,但还没有看到对这种行为的解释 在下面的代码示例中,我正在创建一个闭包,其中包含一个变量Javascript 返回一个闭包';s变量正在创建副本而不是引用,javascript,closures,Javascript,Closures,我被这种闭包行为弄糊涂了。我已经阅读了好几篇SO文章(包括)和MDN关于闭包的文档,但还没有看到对这种行为的解释 在下面的代码示例中,我正在创建一个闭包,其中包含一个变量cache,一个修改它的函数preload,以及一个记录其值的函数report。它还将引用附加到传入的对象 'use strict'; var o = {}; (function(obj) { var cache = {'initialized': false}; function preload(asse
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);
“严格使用”;
var o={};
(功能(obj){
变量缓存={'initialized':false};
功能预加载(资产,完成){
log('preload.Value of cache's',cache);
缓存={};
对于(var i=0;i
我的期望是基于我的理解,当闭包将缓存
附加到提供的obj
时,它将引用分配给闭包内的变量。但是我看到的行为表明,obj.cache
正在获取闭包的cache
的副本
调用
obj.cache=cache时,在哪一点创建了缓存的副本?为什么
在开始时,您正在使obj.cache
指向cache
指向的同一对象(此对象:{'initialized':false}
)
然后,稍后调用preload
时,将变量cache
指向另一个新对象:cache={}代码>。现在,cache
变量指向一个全新的对象,而obj.cache
仍然指向一开始创建的旧对象
这就解释了为什么在闭包内的cache
上完成的所有日志记录都会记录新的值,而日志记录obj.cache
仍然显示未更改的值。它们现在指向两个不同的对象,并且更改cache
现在指向的对象的内容对原始对象hasobj.cache
指向的对象没有影响。当您调用obj.cache=cache
在开始时,您正在使obj.cache
指向cache
指向的同一对象(此对象:{'initialized':false}
)
然后,稍后调用preload
时,将变量cache
指向另一个新对象:cache={}代码>。现在,cache
变量指向一个全新的对象,而obj.cache
仍然指向一开始创建的旧对象
这就解释了为什么在闭包内的cache
上完成的所有日志记录都会记录新的值,而日志记录obj.cache
仍然显示未更改的值。它们现在指向两个不同的对象,并且更改cache
现在指向的对象的内容对原始对象hasobj.cache
指向的对象没有影响。在执行IIFE
时,您已经将cache
添加到obj.cache
中,就是这样obj.cache
不包含对IIFE
中cache
变量的引用。但是,report
和preload
函数正在使用cache
变量从IIFE
,即使在创建它们的范围之外调用它们。因此,对于obj.preload
和obj.report
函数(这是观察闭包的地方),将保留对iLife
内作用域的引用,但对于obj.cache
则不保留
有关观察和执行闭包的各种情况的更多详细信息,请查看此信息。在执行iLife
时,您已将cache
添加到obj.cache
,就是这样obj.cache
不包含对IIFE
中cache
变量的引用。但是,report
和preload
函数正在使用cache
变量从IIFE
,即使在创建它们的范围之外调用它们。因此,对于obj.preload
和obj.report
函数(这是观察闭包的地方),将保留对iLife
内作用域的引用,但对于obj.cache
则不保留
有关如何观察和执行闭包的各种情况的更多详细信息,请查看此项。为什么不公开get_cache
,而是公开cache
变量的初始值?因为您正在复制:cache={}
。请注意,唯一的闭包是变量缓存
本身。变量obj.cache
不是闭包,而是一个普通的引用/指针赋值,就像在C、Java或其他语言中一样。因此,它使obj.cache
指向cache
指向的同一对象,而不是变量cache
本身。换句话说,obj.cache=cache
将指针按值分配给cache(它会像大多数编程语言一样复制指针),为什么不公开get_cache
而公开cache
变量的初始值?因为您正在生成一个c