关闭不保持国家变化

时间:2017-04-09 01:49:27

标签: javascript

我以为我理解了闭包,但突然之间的一些简单似乎并没有起作用。

我使用闭包创建了一个单例。这是一个非常缩小的版本:

    Foobar = function() {
        var data = null;

        function init(obj) {
            data = obj;
        }

        return {
            init: init,
            currentValue: data
        }
    }();

由于它是一个单身人士,我希望当我打电话给' init'功能,数据的价值'将在唯一存在的对象中进行更改,并且在使用' currentValue'的后续检索中该值仍然可用。

这是我的测试:

    Foobar.init({id:3});
    var test = Foobar.currentValue;

当我在Firefox(F12)中逐步执行此代码时,我可以看到是 - '数据'对于init函数是可见的,并且当我执行' init'时它正在改变该变量。但是,退出init函数并返回执行第二行测试后,var' test'被指定为null(创建单例时的原始值)而不是我传递给" init'的对象的副本。功能,正如我所料。

有人可以解决我的困惑吗?

3 个答案:

答案 0 :(得分:1)

问题是在返回的对象中放置数据会在函数首次执行时保存值 - 这是null。

为了读取数据变量的当前值,currentValue必须是一个函数,如init。

Foobar = function() {
        var data = null;

        function init(obj) {
                data = obj;
        }

        function currentValue() {
                return data;
        }

        return {
                init: init,
                currentValue: currentValue
        }
}();
console.log(Foobar);
Foobar.init({id:3});
var test = Foobar.currentValue();
console.log(Foobar,test);

答案 1 :(得分:1)

我认为你在这里混淆了两个不同的东西 - 也就是说,我认为你正在通过引用和#34; Javascript传递对象。和#34; Javascript关闭"困惑。

回答你的主要问题 - 问题是你在实例化时一次返回变量的值,然后再也不会。所以更新它不会改变任何东西。相反,如果您创建一个返回值的函数,您将看到它正在更新:



Foobar = function() {
        var data = null;

        function init(obj) {
            data = obj;
        }

        function getCurrentValue() {
            return data; 
        }
  

        return {
            init: init,
            getCurrentValue: getCurrentValue
        }
    }();
    
    Foobar.init({id:3});
    console.log(Foobar.getCurrentValue());




现在,如果 data被初始化为对象,而您的init只是以某种方式扩展该对象,那么属性本身将在第一个示例中进行更新,因为它始终在整个生命周期中引用同一个对象:



Foobar = function() {
        var data = {};

        function init(obj) {
            data.id = obj.id;
        }

        return {
            init: init,
            currentValue: data
        }
    }();
    
    Foobar.init({id:3});
    console.log(Foobar.currentValue);




答案 2 :(得分:1)

开始
var Foobar = function () {...}();

该陈述可以分解为

var Foobar;
Foobar = function () {...}();

在第一行,Global范围注册了没有rhs引用的Foobar,因此在立即调用函数表达式(IIFE)之前的任何地方都没有定义Foobar。

在第二行,执行IIFE后,Foobar被分配给IIFE的返回对象,如下所示。

console.log(Foobar); // undefined
var Foobar = function () {...}();
console.log(Foobar); // Object {currentValue: null, init: function}

此时IIFE的返回对象可以显示为

Click to show Diagram of Initial Foobar

然后,当 Foobar.init({id:3})时,执行。 Foobar的初始化将要求rhs参考,这恰好是IIFE的初始化。 init已关闭数据并最终将数据设置为 {id:3}

Click to show Diagram of after Foobar.init

因此

var test = Foobar.currentValue;

显然仍然是 null 值作为其初始状态。

使它符合我们的期望。 anied提及至少有两种可能的解决方案。

  1. 在IIFE中创建另一个功能,并关闭数据 检索它们。
  2. 不是将数据分配给新对象,而是直接使用IIFE的init 操纵同一个对象本身。