关于 LocalStorage 的一些思考

今天又看了一下 LocalStorage ,LocalStorage 是 HTML5 提供的客户端存储数据的新方法。它主要有五个方法:

  • LocalStorage.clear() 不接收参数,无返回值。作用是将所有保存的数据清理。
  • LocalStorage.getItem(keyName) 接收一个键名 返回键名的值 ,键和值都是String,确切的说,都是 DOMString
  • LocalStorage.key(key) 接收一个 integer 型参数,返回LocalStorage中第 n(key)条数据的值。LocalStorage中数据的排序是按被添加的顺序排列的。这个方法并不可靠。
  • LocalStorage.removeItem(keyName); 接收一个键名,无返回值。作用是将该条数据从LocalStorage中移除。
  • LocalStorage.setItem(keyName, keyValue);接收键名和键值,无返回值。将数据保存到本地LocalStorage。

LocalStorage内部实现我并不了解,假设它的setItem内部会调用一个方法,将数据保存到本地中。 我要说的是它的一个有趣的事情:

 LocalStorage.keyName = keyValue

我发现除了setItem以外,还可以直接给LocalStorage对象添加属性,一样可以保存到LocalStorage,之后用LocalStorage.getItem(keyName)一样可以取到这条数据。 我说假设setItem内部会有方法将键值对存储到本地,或者就是单纯的为LocalStorage添加属性时,它一样可以将新添加的属性保存到本地。

那么,我们的JavaScript有什么办法可以在为对象新加属性的时候,触发一个事件吗?是没有的。

setter / getter

setter / get

JavaScript中有 getter 和 setter 可以用来修改对象属性的读写操作。

var o = {
  storage : {
    somePorperty:'123'
    },
  setItem:function(key, val){
    this.storage[key] = val
    },
  getItem:function(key){
    return this.storage[key]
    }
}
Object.defineProperty(o, 'somePorperty',{
  get: function() {return o.storage.somePorperty},
  set: function(newValue) { return o.storage.somePorperty = newValue},
  enumerable: true,
  configurable: true
})

o.getItem('somePorperty')
 >> "123"
o.somePorperty
 >> "123"
o.setItem('somePorperty', 234)
 >> undefined
o.somePorperty
 >> 234

Object.defineProperty就是用来为对象定义属性的操作方法,不过用它能否为自定义对象实现类似LocalStorage的方法呢,答案是不能的:Object.defineProperty必须明确指出属性名作为它的第二个参数,对于在对象上后天的属性则无能为力了。

Proxy

在我查询了很多内容之后,终于发现了解决方案。 那就是ES6 的 Proxy

Proxy 对象被用来定义基本操作(如查找,分配,枚举函数调用等),以及自定义行为。

简单来说,使用了Proxy之后,添加属性,更改属性等等基础操作,都是可以被截获并修改默认操作的。下边就是我实现的一个类似LocalStorage的setItem,getItem的方法。

    let porpertiesListner = {
    set: function (obj, prop, value) {
        if (prop !== 'setItem' && prop !== 'storage' && prop !== 'getItem') {
            obj.setItem(prop, value)
        }
    },
    get: function (obj, prop) {
        if (prop == 'setItem' || prop == 'getItem'|| prop == 'storage') {
            return obj[prop]
        }else {
            return obj.storage[prop]
        }
    }
    }

    let person = new Proxy({
        storage: {},
        setItem: function (prop, value) {
            this.storage[prop] = value;
        },
        getItem: function (prop) {
            return this.storage[prop];
        }
    }, porpertiesListner);


    console.log('方法测试')
    person.test1 = '123'
    console.log('person.test1 ' + person.test1)
    console.log("person.getItem('test1') " + person.getItem('test1'))

    person.setItem('test2','234')
    console.log('person.test2 ' + person.test2)
    console.log("person.getItem('test2') " + person.getItem('test2'))

我可以预计,Proxy在今后的开发中可以大放异彩,因为我们对对象可以控制的更多了。

Proxy的支持情况

由于ES5的限制,polyfill也无法实现Proxy。所以Babel是不支持Proxy的。 但是呢最新款的浏览器已经支持了,具体可以查看这里,包括Edge ,Firefox45, Chrome 50 都已经支持了。

Written on April 15, 2016