2

我想创建一个可以保存和加载其状态(到本地存储)的 Javascript 对象。

这是我正在使用的基本模式:

var obj = function () {

    // private members
    //

    return {

        // public members

        load: function () {
            this.state = JSON.parse(localStorage.getItem('obj'));

            if (this.state === null) {
                this.state = {
                    name: 'foo'
                };
            }
        },

        save: function () {
            localStorage.setItem('obj', JSON.stringify(this.state));
        }
    };
}();

// load state
obj.load();
console.log(obj.state.name);

// save state
obj.state.name = 'bar';
obj.save();

但是有一点让我对这种模式感到恼火:我必须通过“状态”属性访问对象的持久属性。

我该如何重写它,以便我可以以更自然的方式使用该对象,例如:

// load state
obj.load();
console.log(obj.name);

// save state
obj.name = 'bar';
obj.save();

这是一个非常简单的“状态”,但该解决方案必须适用于具有嵌套对象、数组等的复杂状态对象,因此简单地向我的对象添加一个“名称”属性并不是我想要的。

4

4 回答 4

2

如果您不关心加载/保存哪些属性,那么您可以简单地将所有属性从状态复制到 self. 例如,在阅读之后var state(而不是this.state因为你不想state再成为其中的一部分this):for(x in state) this[x] = state[x];

同样,您可以节省:var state = {}; for(x in this) state[x] = this[x]

但是,如果您想要一个预定义的列表,那么我建议:var fields = ['name', 'zip', 'age'];

然后使用for(x in fields) this[x] = state[x]加载和for(x in fields) state[x] = this[x];保存。

对不起,它有点拼凑起来,但我希望你能理解我的意思:)

编辑:为每个 OPs 请求添加了完整的示例。

使用此技术的完整解决方案示例如下:

var obj = function () {

    // private members
    //

    return {

        // public members

        load: function () {
            var state = JSON.parse(localStorage.getItem('obj'));

            if(state == null) state = { name: 'foo' };

            for(x in state) this[x] = state[x];
        },

        save: function ()
        {
            var state = {};

            // check if it's a function.  This version taken from underscorejs
            var isFunction = function(obj) {
                return !!(obj && obj.constructor && obj.call && obj.apply);
            };

            for(x in this)
            {
               if(isFunction(this[x])) continue; // skip functions

               state[x] = this[x];
            }

            localStorage.setItem('obj', JSON.stringify(state));
        }
    };
};
于 2012-12-06T19:17:38.650 回答
2

您还可以在属性更改时完成直接保存,通过使用 ES5 getter/setter 或使用Watch.js

Watch.js 示例:

var obj = (function () {
    // private members
    //
    var self = {
        // Some properties
        name: '',
        otherName: '',            
        // Try to load state or use "foo state"
        state: JSON.parse(localStorage.getItem('obj')) || {
                    name: 'foo'
        },            
        save: function () {
            localStorage.setItem('obj', JSON.stringify(this.state));
        }
    };
    // Watch the object and save it to local storage, when a property changes
    // (Of course, you don't need to call the save method here...)
    watch(self, function(property, value) {        
        console.log('saving state!');
        self.state[property] = value;            
        self.save();
    });

    return self;
}());

// Update some properties and see that it is saved to local storage.
obj.name = "Some name";
obj.otherName = "Some other name";    
console.log(JSON.parse(localStorage.getItem('obj')));

​ JsFiddle上的示例。

于 2012-12-06T20:40:17.830 回答
0

您可以制作state内部和表面的 getter 和 setter:

var obj = function () {
    // private members
    var state = {};

    return {
        // public members
        load: function () {
            var loadedState = JSON.parse(localStorage.getItem('obj'));

            if (loadedState === null) {
                state = {
                    name: 'foo'
                };
            } else {
                state = loadedState;
            }
        },
        save: function () {
            localStorage.setItem('obj', JSON.stringify(state));
        },
        getState: function (key) {
            return state[key];
        },
        setState: function (key, value) {
            state[key] = value;
        }
    };
};
于 2012-12-06T19:25:04.067 回答
0

使用jQuery 的 extend()

var obj = (function () {
    return {
        load: function () {
            var stored = localStorage.getItem("obj");
            var state = stored ? JSON.parse(stored) : {
                name: 'foo'
            };
            $.extend(this, state);
        },

        save: function () {
            localStorage.setItem("obj", JSON.stringify(this));
        }
    };
})();

// load state
obj.load();
console.log(obj);

// save state
obj.name = 'bar';
obj.save();

jsfiddle

所有功劳归功于 pimvdb。

于 2012-12-06T20:01:47.247 回答