什么是WebStorageProxy?

大家好。今天很高兴能向大家介绍一个全新的JavaScript工具库。它的名字是 webstorage-proxy.js 。这也是我第一次开发JavaScript工具库,期间遇到不少问题,当然更多的是收获。下面由我来为大家分享下这个js库的由来和使用,以及开发过程遇到的问题和总结的经验吧。

WebStorageProxy简介

引入webstorage-proxy.js,window上就有了一个叫 WebStorageProxy 的类。WebStorageProxy ,顾名思义。就是webstorage 代理器。webstorage 是H5的一个浏览器API,关于它的使用可以参考:HTML5本地存储session,cookie,sessionStorage,localStorage的区别及应用场景。代理器(Proxy)是ES6的API,用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。传送门~ 这里就不赘述了。

WebStorageProxy 做的就是把 sessionStorage/localStorage 的内容映射到一个对象上,最后返回这个对象的代理器。然后当你想要操作 sessionStorage/localStorage时, 你只需要用操作对象的方式操作这个代理器,操作的结果就会映射到 sessionStorage/localStorage 上。

说起来感觉有点绕,其实用起来非常简单。只需要这样:

<script src="./webstorage-proxy.js"></script>
<script>
    const storage = new WebStorageProxy('sessionStorage')

    console.log(sessionStorage.getItem('name')) //null

    storage.name = 'yinchengnuo'
    console.log(sessionStorage.getItem('name')) //yinchengnuo

    delete storage.name  //true
    console.log(sessionStorage.getItem('name')) //null
</script>

以上就是 WebStorageProxy 最简单的使用。有了 WebStorageProxy,你就可以用操作对象的方式操作sessionStorage和localStorage了。WebStorageProxy 的原理是通过 Proxy 劫持了对 WebStorageProxy 实例的操作,然后实时映射到 WebStorage 上。有没有点 Vue 的感觉?这就使得我们在操作存储一些对象数组数据时十分方便:

<script src="./webstorage-proxy.js"></script>
<script>
    const storage = new WebStorageProxy('sessionStorage')
    storage.data= {
        name: 'yinchengnuo',
        age: 23,
        skills: ['web', 'guitar']
    }
    console.log(storage.data)  
    //{
    //    name: 'yinchengnuo',
    //    age: 23,
    //    skills: ['web', 'guitar']
    //}
</script>

我们在浏览器里看下数据:

就这样,省去了操作原生WebStorage存取对象时繁琐的JSON操作。相当之方便!而且 WebStorageProxy 做的远不止这些,除了刚刚向大家展示的 数据劫持 功能,WebStorageProxy 还支持 同页面监听sessionStorage/localStorage生命周期函数监听数据变动命名空间数据加密等功能。下面我会一一为大家介绍这些功能的用法,和 WebStorageProxy 的API。先说下怎么安装吧!

WebStorageProxy安装

你可以通过一个CDN地址引入这个库:

<script src="https://cdn.jsdelivr.net/npm/@yinchengnuo/webstorage-proxy@1.0.4/dist/webstorage-proxy.min.js"></script>

 如果你对源码感兴趣,也可以去GitHub上克隆这个项目:

git clone git@github.com:yinchengnuo/webstorage-proxy.git

API 

方法参数描述
allnull返回一个新对象,里面包含实例的所有数据
hasstring返回一个布尔值,表示实例里面是否有指定的 key
clearnull清空实例和 webStorage里面的 的所有数据

 示例

const storage = new WebStorageProxy('sessionStorage')
storage.data= {
	name: 'yinchengnuo',
	age: 23,
	skills: ['web', 'guitar']
}
console.log(storage.all(), storage.has('name'))
//{
//	name: "yinchengnuo",
//	age: 23,
//	skills: ["web","guitar"]
//}
console.log(storage.has('name'))
//false

storage.clear()
console.log(storage.all())
//{}
consle.log(sessionStorage.getItem('data'))
//null

实例化配置

WebStorageProxy 最多可以接收两个参数

当参数为两个时,第一个必须是一个值为 'sessionStorage' 或 'localStorage'的字符串,第二个参数为字符串或返回字符串的函数作为命名空间。如果参数为函数时,这个函数会接收一个数组,这个数组里包含当前 storage 所有的命名空间:

const storage1 = new WebStorageProxy('sessionStorage','namespace1')
const storage2 = new WebStorageProxy('sessionStorage',namespace => {
	console.log(namespace) //['namespace1']
	return 'namespace2'
})

 当参数为一个时,这个参数可以是是一个值为 'sessionStorage' 或 'localStorage'的字符串,就像上面据的几个例子一样。同时也可以是一个配置对象。完整的配置对象长这个样子:

//配置对象中的可配置函数分为两种:
//1. 生命周期函数,每个实例只执行一次
//2. 数据监听函数。可在实例生成后追加多个,非箭头函数时this指向操作的key所在的代理对象。
const storage1 = new WebStorageProxy({
	type: 'sessionStorage',
	namespace: 'yinchengnuo',
	beforeCreate() {
		//生命周期函数。非箭头函数时this指向window。在实例生成之前执行。
	},
	created() {
		//生命周期函数。非箭头函数时this指向实例对象。在实例生成之后执行。
	},
	beforeGet(key) {
		//数据监听函数。接收要获取key作为参数。在get操作执行之前执行
	},
	geted(key) {
		//数据监听函数。接收要获取的key作为参数。在get操作执行之后执行
	},
	beforeSet() {
		//数据监听函数。接收要设置的key和value作为参数。在set操作执行之前执行。
	},
	proxySeted() {
		//数据监听函数。接收要设置的key和value作为参数。在set操作执行之后执行。
	},
	storageSeted() {
		//数据监听函数。接收要设置的key和value作为参数。在代理对象上的数据映射到webStorage上之后执行。
	},
	beforeDel() {
		//数据监听函数。接收要删除的key作为参数。在delete操作执行之前执行。
	},
	proxyDeled() {
		//数据监听函数。接收要删除的key作为参数。在delete操作执行之后执行。
	},
	storageDeled() {
		//数据监听函数。接收要删除的key作为参数。在代理对象上的数据映射到webStorage上之后执行。
	},
	storageChanged() {
		//数据监听函数。在 type 里指定类型的 Storage 实力发生变化时执行。接收一个事件对象作为参数。
	},
	beforeDestroy() {
		//生命周期函数。非箭头函数时this指向实例对象
	},
	destroyed() {
		//生命周期函数。非箭头函数时this指向window
	}
})

这些配置对象里的钩子函数看起来很多,其实只有两类:生命周期函数和数据监听函数。

生命周期函数只能在实例化时通过配置对象设置,每个生命周期函数在实例对象的生命周期内只执行一次。有四个,分别是:beforeCreatecreatedbeforeDestroydestroyed。 数据监听函数不仅仅可以通过实例配置对象设置,也可以在实例化对象生成之后通过赋值的形式追加多个。有9个。分别用于监听4种行为种:get、set、delete和storagechange。9个函数分别是:beforeGetgetedbeforeSetproxySetedstorageSetedbeforeDelproxyDeledstorageDeled,最后一个是storageChanged。 关于这些配置函数的用法会在后面的部分一一讲解。

生命周期函数

通过上面的几个小例子,你大概也能知道。在实例化 WebStorageProxy 时,beforeCreatecreated会被相继触发。

const storage = new WebStorageProxy({
	type: 'sessionStorage',
	beforeCreate() {
		console.log('beforeCreate')  //'beforeCreate'
	},
	created() {
		console.log('created')  //'created'
	}
})

但是beforeDestroydestroyed呢?它们何时触发呢?即,如何销毁一个 WebStorageProxy ?你可以使用 destory(del,bool) 方法:

destory(del, bool)

const storage = new WebStorageProxy({
	type: 'sessionStorage',
	beforeDestroy() {
		console.log('beforeDestroy')  //'beforeCreate'
	},
	destroyed() {
		console.log('destroyed')  //'created'
	}
})
storage.name = 'yinchengnuo'
storage.name  //'yinchengnuo'
storage.destory()
storage.name  //Uncaught TypeError: Cannot perform 'get' on a proxy that has been revoked

destory(del, bool)方法接收两个参数。都为布尔值。 第一个参数表示是否在销毁 实例化对象时清除 WebStorage 里面的数据。 第二个参数表示 是否将 Storage.prototype 上的方法,恢复为原生方法。(在 同页面监听sessionStorage/localStorage 部分会有讲解。不建议使用此参数!)。

数据监听

WebStorageProxy 提供了丰富的数据监听函数,可以让你时刻监听你的数据动向。

但事实上,我个人并不建议你过多的使用这些函数。这些函数的出现只是为了在开发这个工具库的时候方便监控数据变动。但是考虑到这个工具库还不成熟,可能存在未知的风险。因此索性将这些钩子函数暴露出来,在你使用过程中如果出现未知问题就可以实时调控

因为是监听数据变动,那么这些钩子函数就不能像实例的生命周期函数一样:一个实例只执行一次,而且只能在实例化时的配置对象里定义。我希望它能够更灵活一些。毕竟这个工具库开发的初衷之一就是为了方便。于是你除了可以在通过在实例化时的配置对象里定义以外,还可以这样做:

const storage = new WebStorageProxy({
	type: 'sessionStorage',
	beforeSet (key, value) {
		console.log('beforeSet', key, value)
	}
})

storage.beforeSet = (key, value) => console.log('beforeSet1', key, value)
storage.beforeSet = (key, value) => console.log('beforeSet2', key, value)
storage.beforeSet = (key, value) => console.log('beforeSet3', key, value)
storage.name = 'yinchengnuo'
//'beforeSet', 'name', 'yinchengnuo'
//'beforeSet1', 'name', 'yinchengnuo'
//'beforeSet1', 'name', 'yinchengnuo'
//'beforeSet1', 'name', 'yinchengnuo'

是的,你不仅可以在实例化时的配置对象里定义的同时,在实例对象上追加钩子函数,而且还可以追加多个。原因很简单:

*WebStorageProxy 在实例化对象的过程中会把实例对象的数据监听函数属性包装成一个类数组并添加代理,使得 set 行为变为 push 行为,并在适当的时候遍历这个类数组执行里面的函数

所以(我们以 beforeSet 为例),实例化对象产生以后。这个对象上的 beforeSet 属性就是一个类数组了, 类数组里面的函数相互独立,互不影响。给 beforeSet 属性赋值就是在向这个类数组里面添加钩子函数。还是上面的例子:

const storage = new WebStorageProxy({
	type: 'sessionStorage',
	beforeSet (key, value) {
		console.log('beforeSet', key, value)
	}
})

storage.beforeSet = (key, value) => console.log('beforeSet1', key, value)

storage.beforeSets[0]
//beforeSet (key, value) {
//	console.log('beforeSet', key, value)
//}
storage.beforeSets[0]  //(key, value) => console.log('beforeSet1', key, value)

需要注意的是:追加的钩子函数名和函数值必须合法。当前版本的 WebStorageProxy 不支持删改数据监听钩子函数类数组里的函数,只允许添加

同页面监听sessionStorage/localStorage

H5在新增了 WebStorage 的同时,也为 WebStorage 提供了事件支持。但是原生的 window 上的 storage 事件只能监听到同域下不同页面操作 localStorage 行为。同一个 session 下操作 sessionStorage 和 localStorage 都是监听不到。我们来看下MDN是怎么说的:

当前页面使用的storage被其他页面修改时会触发StorageEvent事件。

这是原话,就这一句。一开始我就很好奇。为什么H5不提供同页面的事件监听呢?但是后来想了下,感觉没必要。因为 WebStorage的读写操作都是同步的,而且不能跨域,都是在一个页面里,操作就操作了,好像确实没什么必要监听。

但是,随着前端的发展,各种SPA的出现,应该会有不同路由或组件的状态需要根据 WebStorage 的状态变化的业务场景出现,这也是这个 js 库开发的初衷之一,做出来以防万一嘛。

那 WebStorageProxy 是如何监听 WebStorage 变化的呢?其实很简单,就是重写 Storage.protoytpe 上面的方法,让它们在适当的时候触发 window 上的自定义事件。这两个自定义事件分别是 sessionstoragechange 和 localstoragechange 。你可以监听他们,前提是必须实例化一次 WebStorageProxy:

<script src="./webstorage-proxy.js"></script>
<script>
    new WebStorageProxy('sessionStorage')

    window.addEventListener('sessionstoragechange', e => {
        console.log(`
            sessionstoragechange, 
            key: ${e.key},
            newValue: ${e.newValue}, 
            oldValue: ${e.olaValue}
        `)
    })
    window.addEventListener('localstoragechange', e => {
        console.log(`
            localstoragechange, 
            key: ${e.key},
            newValue: ${e.newValue}, 
            oldValue: ${e.olaValue}
        `)
    })
    sessionStorage.setItem('name', 'yinchengnuo')  
    //'sessionstoragechange, key: name, newValue: yinchengnuo, oldValue: null'

    localStorage.setItem('name', 'yinchengnuo')
    //'localstoragechange, key: name, newValue: yinchengnuo, oldValue: null'
</script>

这个功能无论是实现起来还是使用起来还是一如既往的简单。部分源码:

    Storage.prototype.setItem = function(key, value) {
        if (!isPrivate(proto, key)) {
            let oldValue = this[proto._GETITEM](key)
            if (oldValue !== value) {
                this[proto._SETITEM](key, value)
                this[proto._GETITEM](proto._WEBSTORAGEPROXY_INDENT_STORAGE).match(/sessionStorage/i) && dispatch.call(this, 'sessionstoragechange', this, key, value, oldValue)
                this[proto._GETITEM](proto._WEBSTORAGEPROXY_INDENT_STORAGE).match(/localStorage/i) && dispatch.call(this, 'localstoragechange', this, key, value, oldValue)
                return true
            }
        }
        return false
    }

当然,如果你还记得刚刚我们说过的数据监听那块。你应该还记得:数据监听函数中有一个 storageChanged 函数。没错,你也可以这样使用它:

<script src="./webstorage-proxy.js"></script>
<script>
    const storage = new WebStorageProxy('sessionStorage')

    storage.storageChanged = e => console.log('listener1')
    storage.storageChanged = e => console.log('listener2')    
    storage.storageChanged = e => console.log('listener3')

    storage.name = 'yinchengnuo'
    //'listener1' 'listener2' 'listener3'
</script>

命名空间

为社么要使用命名空间?

  1. 命名空间是数据加密的基础
  2. 使用命名空间在数据变动时可以减少一次遍历,提升一些性能
  3. 便于多人协作开发

便于多人协作开发这个就不赘述了,我学前端时第一次知道这个命名空间概念时,他就是为了解决多人协作开发了。但是为什么命名空间是数据加密的基础呢?(WebStorageProxy 提供了数据加密功能,但是只能加密命名空间之中的数据。详细介绍在下一部分)

假设我们现在没有使用命名空间:

sessionStorage.name = 'sessionStorage'
const storage = new WebStorageProxy('sessionStorage')

storage.name  //'sessionStorage'

如果在我们实例化 WebStorageProxy 对象之前。WebSorage 中已经存在了一些数据。而实例化 WebStorageProxy 之后,这些数据是会被全部映射到 WebStorageProxy 实例对象上的。如果我们采用了加密策略,那么 WebStorageProxy 实例对象修改这些已经存在的数据势必会启用加密算法。如果此时还有一些别的程序正在依赖这些数据,而它们并没有实例化 WebStorageProxy 对象。那他们在读取这些数据时势必会报错。因为它们没有对称解密函数。

你可以把不使用命名空间时 WebStorageProxy 实例对象的状态想象为全局。使用命名空间时 WebStorageProxy 实例对象的状态想象为局部。当全局里面的数据一部分来自原有的,一部分来自 WebStorageProxy 实例对象。那么如果我们支持不使用命名空间也能加密的话,就势必要时刻监控每个变量的状态变化,哪个是原有的数据,哪个是实例的数据,哪个从原有的数据变为了实例的数据。如果这样做,那么程序就会变得极其复杂。而且我们为 WebStorageProxy 实例对象提供了 destory 方法,而在 destory 之前究竟要不要对已经加密的数据进行解密处理?这又是一个问题!所以,出于这么多方面的考虑。我将 WebStorageProxy 设计为在不使用命名空间时, 不能使用加密策略。

使用命名空间就意味着私密,只有 WebStorageProxy 实例对象才能访问。事实上也正是如此:

new WebStorageProxy('sessionStorage','yinchengnuo')

当你执行了上面的代码,打开控制台。你就会发现 sessionStorage 里面多了一条数据,它的 key 为:

_WEBSTORAGEPROXY_NAMESPACE:yinchengnuo

value 为空。现在让我们尝试获取它一下:

new WebStorageProxy('sessionStorage','yinchengnuo')
sessionStorage.getItem('_WEBSTORAGEPROXY_NAMESPACE:yinchengnuo')  //false

是的,是 false。因为在 实例化 WebStorageProxy 的时候,WebStorageProxy 已经重写了 Storage.prototype 上面的 clear()、getItem()、setItem()、removeItem()四个方法。使得它们在处理指定 key 值的数据时会选择忽略。因此使用命名空间就意味着私密,除了 WebStorageProxy 实例,外部无法修改。 但是并不是真的无法修改,因为我们在重写这四个方法的同时并没有丢弃它们,而是用另外一种方式将它们放在了 Storage.prototype 上。如果这个时候你在控制台输入 Storage。prototype 并回车的话,就会看到 Storage。prototype 上面多了四个属性:

  • Symbol('clear')
  • Symbol('getItem')
  • Symbol('setItem')
  • Symbol('removeItem')

没错,这四个属性值就是原生的 clear()、getItem()、setItem()、removeItem()四个方法。如何使用它们呢?看下源码就知道了:

WebStorageProxy.prototype._CLEAR = Symbol('clear') 
WebStorageProxy.prototype._GETITEM = Symbol('getItem')
WebStorageProxy.prototype._SETITEM = Symbol('setItem')
WebStorageProxy.prototype._REMOVEITEM = Symbol('removeItem')

没错,我把 Storage.prototype 上四个存储原生方法的属性名得引用放在 WebStorageProxy.prototype 上。这样就能进一步保证这四个方法的安全。如果你想恢复这四个方法,只需要在销毁实例时,将 destory 方法的第二个参数设置为 true 就好了。那么现在我们再来获取下 _WEBSTORAGEPROXY_NAMESPACE:yinchengnuo 的值看一看:

new WebStorageProxy('sessionStorage','yinchengnuo')
sessionStorage[WebStorageProxy.prototype._GETITEM]('_WEBSTORAGEPROXY_NAMESPACE:yinchengnuo')  //''

这样就能获取命名空间的值了。当然 WebStorageProxy 也提供了一些 API 来操作命名空间。

方法参数描述
usestring/null切换命名空间,参数为空时不使用命名空间(切换到全局)
delstring删除命名空间,参数为要删除的命名空间名字。如果为当前命名空间,删除前自动执行use()
namespacenull返回当前命名空间的名字
namespacesnull返回所有命名空间的名字

数据加密

WebStorageProxy 支持自定义的加密策略。允许使用自定义函数来对命名空间之中的数据进行存储。

首先你需要准备两个纯函数,用于加密解密字符串。比如我准备的两个:

const encryption = str => {
	let string = escape(str)
	let len = string.length;
	let result = ''
	for (let i = 0; i < len; i ++) {
		result += String.fromCharCode(string.charCodeAt(i) + i + 23)
	}
	return result
}
const decryption = str => {
	let string = str
	let len = string.length;
	let result = ''
	for (let i = 0; i < len; i ++) {
		result += String.fromCharCode(string.charCodeAt(i) - i - 23)
	}
	return unescape(result)
}

然后在实例化 WebStorageProxy 之前调用 WebStorageProxy 上的 crypto() 方法:

ebStorageProxy.crypto(encryption, decryption)

一定要保证在全局第一次实例化 WebStorageProxy 之前调用 crypto() ,否则加密策略不生效。也因此一个 session 只允许一种加密策略

此时我们再来看一看,被加密之后的数据变成什么样了:

let storage = new WebStorageProxy('sessionStorage','yinchengnuo')
storage.data= {
	name: 'yinchengnuo',
	age: 23,
	skills: ['web', 'guitar']
}
sessionStorage[WebStorageProxy.prototype._GETITEM]('_WEBSTORAGEPROXY_NAMESPACE:yinchengnuo')
//<O[?MN����FTUIXgL_kO]^� �¨ªWefZix]p|`no¬ ­¦guvjy�m{|ĵ»±·µ¿¹ÁÉÄ{��~�����ÀÇÆ�����¨����¯� ¡ãÜÛßàè�©ª�­¼¡²À¤²³ùè檸¹­»Í°¾¿õĄùąóą¹ÇȼÍÝ¿ÒàÂÕãÅØæ

是的,使用加密策略之后。存储到 webStorage 里的数据就变成了一堆乱码。如果有人或者脚本想要窃取你的数据。那他可能就要费点功夫了。数据加密的使用也还是一如以往的简单。但是你可能会问一个问题:那就是 WebStorageProxy 提供的加密策略足够安全嘛?

安全问题

WebStorageProxy强烈不建议你将敏感数据保存在本地。同时也不能保证你存储在本地的加密数据绝对安全。因为这不仅仅取决于于你提供的加密函数,而且这种加密解密的过程类似密钥为加密解密函数的对称加密算法。一旦你的密钥(加密解密函数算法)泄露,数据加密也就失去了意义。同时加密数据也不是 WebStorageProxy 开发的初衷。如果你熟悉 WebStorageProxy 的源码,你会发现解密这些经过加密的数据轻而易举。所以 WebStorageProxy 的加密策略只是为了实现将保存在本地的数据不是明文的形式呈现

来看下源码:

export default new Proxy(WebStorageProxy, {
	get (target, key) {
		if (key === 'crypto') {
			if (!target.prototype.encryption && !Storage.prototype[WebStorageProxy.prototype._GETITEM]) {
				return (...args) => {
					if (args.length == 2 && isFunction(args[0]) && isFunction(args[1])) {
						args.forEach((e, i) => {
							target.prototype[i ? 'decryption' : 'encryption'] = new Proxy(e, {
								apply (target, ctx, args) {
									if (proto(ctx) === WebStorageProxy.prototype) {
										return Reflect.apply(target, ctx, args) 
									}
									return false
								}
							})
						})
						Object.freeze(target.prototype)
					}
				}
			} else {
				return false
			}
		}
		return Reflect.get(target, key)
	}
})

被写入原型链的 decryption() 和 encryption() 方法不能被外部调用。只能被 WebStorageProxy 的实例对象调用。但是你可能记得刚刚我们调用 webStorage 原生方法时:

sessionStorage[WebStorageProxy.prototype._GETITEM]('_WEBSTORAGEPROXY_NAMESPACE:yinchengnuo')

就像这样,我们只要稍微改动一下:

WebStorageProxy.prototype.decryption.call((new WebStorageProxy('localStorage')).__proto__,
 sessionStorage[WebStorageProxy.prototype._GETITEM]('_WEBSTORAGEPROXY_NAMESPACE:yinchengnuo'))
//"{"name":"yinchengnuo","age":23,"skills":["web","guitar"]}"

就解密了经过加密策略加密的数据!!!

总结

好了,以上就是关于这个工具的简单介绍。但是也介绍了所有的API。希望能够在以后的工作中给大家带来便利。当然如果你有更好的想法或者发现了bug,欢迎你 和我联系,万分感谢。下面就和大家分享下,这个工具的由来和开发过程吧。

我一直次使用 WebStorage 的 API 是在几个月前我做一个 vue 实战项目的时候,因为是自己抓包来的数据,做的是一个仿某直播平台的直播webapp,传送门~因为是抓包抓来的数据,所以接口就十分有限。有限到什么程度,就是直播部分,我只搞到了4个接口,分别是:

完全不能和后台交互。因此我只能把所有的数据放在Vuex里,从直播列表页面进入直播间页面传一个索引,进入路由之后再去Vuex里面取。本来这样做没什么不好的,因为这样做方便嘛!于是一切都进行挺正常的,直到有一天不小心在直播间页面点到了刷新。于是,就白屏了!是的因为我只有四个接口,根本不能在刷新后根据id向后台请求数据。然后这个时候vuex也没了,所以白屏了。想办法解决的过程就不说了。最后使用sessionStorage 解决了,于是就有了下面的代码:

就是用 sessionStorage 在进入直播间页面路由之后,把页面的信息能缓存的全存到 sessionStorage 里面去。然后就不怕刷新了。当时我在做这个的时候,确实感觉到了 sessionStorage 相对 cookie 来说方便太多了。但是还不够,毕竟用过vue的都知道vue的数据操作有多便捷。当时我就在想,能不能做一个类似的,就像vue操作数据那样能让我们操作 webStorage 的工具。当时简单找了下,没找到。后台这个练手的项目做完就又去看微信小程序的文档了。就把这事给忘了。直到最近在学习React时,被JSX和Redux搞得头都大了,还有 react 出名的 异步 setState 。使我对使用react 做一个练手的项目提不起一点兴趣。于是我忽然怀念起了几个月前使用vue的美好时光。自然而然就想起来这个工具库了。于是我决定自己做一个JavaScript工具库。

整个项目使用 rollup 构建。项目目录和开发依赖:

运行: npm test 

基本就是这样了。讲真的,开发工具库使用 rollup 体验很不错。因为只需要关注js,同时也没有什么多余的代码,这个库虽然功能不多,代码也不凝练,mini之后gzip的包也只有3KB左右。因此非常推荐大家尝试。

最后总结下我做这个库的总结吧:

1. 使用自动化构建工具 (这个就不用多说了)

2. 尽可能熟悉要用到的底层API  (如本库里用到的Proxy,Storage,StorageEvent,dispatch等)

3. 减少错误提示 (不需为用户传参不合法写很多错误提示)

4. 尽可能不要出现重复代码,哪怕一段代码只重复了两次,也要尽量封装成纯函数 (封装可减少代码体积)

5. 开发的源码一定要写注释越详细越好

6. 在需要一些工具方法比如合并,克隆,类型判断时,尽量自己写。不要引入第三方工具,比如lodash里的方法

7. 测试很重要

8. 设计API时一定要深思熟虑,为什么,能做什么,如何实现

9. 初期的构架很重要,进度很慢是正常的。如果一开始很快,后面问题越做越多。那可能就是开始时你的设计思路不对。

目前,这就是我做这个工具库总结的经验。当然也只是我的个人看法。如果你对你有所帮助是最好的。好了。这篇文章就到这里了。码字不易,如果你觉还可以的话,还请多多点赞,当然,给给 star 也是极好的呢!!!

https://github.com/yinchengnuo/webstorage-proxy

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值