你們好。今天很高興能向你們介紹一個全新的JavaScript工具庫。它的名字是 webstorage-proxy.js 。這也是我第一次開發JavaScript工具庫,期間遇到很多問題,固然更多的是收穫。下面由我來爲你們分享下這個js庫的由來和使用,以及開發過程遇到的問題和總結的經驗吧。前端
引入webstorage-proxy.js,window上就有了一個叫 WebStorageProxy 的類。WebStorageProxy ,顧名思義。就是webstorage 代理器。webstorage 是H5的一個瀏覽器API,關於它的使用能夠參考:HTML5本地存儲,session,cookie,sessionStorage,localStorage的區別及應用場景。代理器(Proxy)是ES6的API,用於定義基本操做的自定義行爲(如屬性查找,賦值,枚舉,函數調用等)。傳送門~ 這裏就不贅述了。vue
WebStorageProxy 作的就是把 sessionStorage/localStorage 的內容映射到一個對象上,最後返回這個對象的代理器。而後當你想要操做 sessionStorage/localStorage時, 你只須要用操做對象的方式操做這個代理器,操做的結果就會映射到 sessionStorage/localStorage 上。react
提及來感受有點繞,其實用起來很是簡單。只須要這樣:git
<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 的感受?這就使得咱們在操做存儲一些對象數組數據時十分方便:github
<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>複製代碼
咱們在瀏覽器裏看下數據:web
就這樣,省去了操做原生WebStorage存取對象時繁瑣的JSON操做。至關之方便!並且 WebStorageProxy 作的遠不止這些,除了剛剛向你們展現的 數據劫持 功能,WebStorageProxy 還支持 同頁面監聽sessionStorage/localStorage、生命週期函數、監聽數據變更、命名空間、數據加密等功能。下面我會一一爲你們介紹這些功能的用法,和 WebStorageProxy 的API。先說下怎麼安裝吧!算法
你能夠經過一個CDN地址引入這個庫:vuex
<script src="cdn.jsdelivr.net/npm/@yinche…"></script>npm
若是你對源碼感興趣,也能夠去GitHub上克隆這個項目:小程序
git clone git@github.com:yinchengnuo/webstorage-proxy.git
方法 | 參數 | 描述 |
---|---|---|
all
|
null | 返回一個新對象,裏面包含實例的全部數據 |
has
|
string | 返回一個布爾值,表示實例裏面是否有指定的 key |
clear
|
null | 清空實例和 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
}
})複製代碼
這些配置對象裏的鉤子函數看起來不少,其實只有兩類:生命週期函數和數據監聽函數。
生命週期函數只能在實例化時經過配置對象設置,每一個生命週期函數在實例對象的生命週期內只執行一次。有四個,分別是:beforeCreate、created、beforeDestroy、destroyed。 數據監聽函數不只僅能夠經過實例配置對象設置,也能夠在實例化對象生成以後經過賦值的形式追加多個。有9個。分別用於監聽4種行爲種:get、set、delete和storagechange。9個函數分別是:beforeGet、geted、beforeSet、proxySeted、storageSeted、beforeDel、proxyDeled、storageDeled,最後一個是storageChanged。 關於這些配置函數的用法會在後面的部分一一講解。
經過上面的幾個小例子,你大概也能知道。在實例化 WebStorageProxy 時,beforeCreate、created會被相繼觸發。
const storage = new WebStorageProxy({
type: 'sessionStorage',
beforeCreate() {
console.log('beforeCreate') //'beforeCreate'
},
created() {
console.log('created') //'created'
}
})複製代碼
可是beforeDestroy、destroyed呢?它們什麼時候觸發呢?即,如何銷燬一個 WebStorageProxy ?你可使用 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 裏面的數據。 第二個參數表示
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)複製代碼
須要注意的是:
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>複製代碼
爲社麼要使用命名空間?
便於多人協做開發這個就不贅述了,我學前端時第一次知道這個命名空間概念時,他就是爲了解決多人協做開發了。可是爲何命名空間是數據加密的基礎呢?(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 上面多了四個屬性:
沒錯,這四個屬性值就是原生的 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 來操做命名空間。
方法 | 參數 | 描述 |
---|---|---|
use
|
string/null | 切換命名空間,參數爲空時不使用命名空間(切換到全局) |
del
|
string | 刪除命名空間,參數爲要刪除的命名空間名字。若是爲當前命名空間,刪除前自動執行use() |
namespace
|
null | 返回當前命名空間的名字 |
namespaces
|
null | 返回全部命名空間的名字 |
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)複製代碼
此時咱們再來看一看,被加密以後的數據變成什麼樣了:
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 提供的加密策略足夠安全嘛?
來看下源碼:
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 也是極好的呢!!!