欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS前端操作 Cookie源碼示例解析

 更新時(shí)間:2022年12月25日 09:24:23   作者:田八  
這篇文章主要為大家介紹了JS前端操作 Cookie源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

前端操作Cookie的場(chǎng)景其實(shí)并不多見(jiàn),Cookie也因?yàn)楦鞣N問(wèn)題被逐漸淘汰,但是我們不用Cookie也可以學(xué)習(xí)一下它的思想,或者通過(guò)這次的源碼來(lái)學(xué)習(xí)其他的一些知識(shí)。

今天帶來(lái)的是:js-cookie

源碼分析

使用

根據(jù)README,我們可以看到js-cookie的使用方式:

// 設(shè)置
Cookies.set('name', 'value');
// 設(shè)置過(guò)期時(shí)間
Cookies.set('name', 'value', { expires: 7 })
// 獲取
Cookies.get('name') // => 'value'
// 獲取所有
Cookies.get() // => { name: 'value' }
// 獲取指定域名下
Cookies.get('foo', { domain: 'sub.example.com' })
// 刪除
Cookies.remove('name')

還有很多其他用和配置說(shuō)明,大家可以自己去看看。

源碼

js-cookie的源碼并不多,src目錄下的api.mjs就是我們要分析的源碼,只有一百行左右。

/* eslint-disable no-var */
import assign from './assign.mjs'
import defaultConverter from './converter.mjs'
function init (converter, defaultAttributes) {
  function set (name, value, attributes) {
    if (typeof document === 'undefined') {
      return
    }
    attributes = assign({}, defaultAttributes, attributes)
    if (typeof attributes.expires === 'number') {
      attributes.expires = new Date(Date.now() + attributes.expires * 864e5)
    }
    if (attributes.expires) {
      attributes.expires = attributes.expires.toUTCString()
    }
    name = encodeURIComponent(name)
      .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
      .replace(/[()]/g, escape)
    var stringifiedAttributes = ''
    for (var attributeName in attributes) {
      if (!attributes[attributeName]) {
        continue
      }
      stringifiedAttributes += '; ' + attributeName
      if (attributes[attributeName] === true) {
        continue
      }
      // Considers RFC 6265 section 5.2:
      // ...
      // 3.  If the remaining unparsed-attributes contains a %x3B (";")
      //     character:
      // Consume the characters of the unparsed-attributes up to,
      // not including, the first %x3B (";") character.
      // ...
      stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]
    }
    return (document.cookie =
      name + '=' + converter.write(value, name) + stringifiedAttributes)
  }
  function get (name) {
    if (typeof document === 'undefined' || (arguments.length && !name)) {
      return
    }
    // To prevent the for loop in the first place assign an empty array
    // in case there are no cookies at all.
    var cookies = document.cookie ? document.cookie.split('; ') : []
    var jar = {}
    for (var i = 0; i < cookies.length; i++) {
      var parts = cookies[i].split('=')
      var value = parts.slice(1).join('=')
      try {
        var found = decodeURIComponent(parts[0])
        jar[found] = converter.read(value, found)
        if (name === found) {
          break
        }
      } catch (e) {}
    }
    return name ? jar[name] : jar
  }
  return Object.create(
    {
      set: set,
      get: get,
      remove: function (name, attributes) {
        set(
          name,
          '',
          assign({}, attributes, {
            expires: -1
          })
        )
      },
      withAttributes: function (attributes) {
        return init(this.converter, assign({}, this.attributes, attributes))
      },
      withConverter: function (converter) {
        return init(assign({}, this.converter, converter), this.attributes)
      }
    },
    {
      attributes: { value: Object.freeze(defaultAttributes) },
      converter: { value: Object.freeze(converter) }
    }
  )
}
export default init(defaultConverter, { path: '/' })
/* eslint-enable no-var */

分析

js-cookie的源碼并不多,我們先來(lái)看看導(dǎo)出的是什么:

export default init(defaultConverter, { path: '/' })

這里是直接導(dǎo)出了init函數(shù)的返回值,我們來(lái)看看init函數(shù)的返回值:

function init (converter, defaultAttributes) {
  // ...
  return Object.create(
    {
      set: set,
      get: get,
      remove: function (name, attributes) {
        set(
          name,
          '',
          assign({}, attributes, {
            expires: -1
          })
        )
      },
      withAttributes: function (attributes) {
        return init(this.converter, assign({}, this.attributes, attributes))
      },
      withConverter: function (converter) {
        return init(assign({}, this.converter, converter), this.attributes)
      }
    },
    {
      attributes: { value: Object.freeze(defaultAttributes) },
      converter: { value: Object.freeze(converter) }
    }
  )
}

這里是使用Object.create創(chuàng)建了一個(gè)對(duì)象,這個(gè)對(duì)象有set、getremove、withAttributes、withConverter這幾個(gè)方法,這幾個(gè)方法都是在init函數(shù)內(nèi)部定義的,我們來(lái)看看這幾個(gè)方法的實(shí)現(xiàn):

set

function set(name, value, attributes) {
    if (typeof document === 'undefined') {
        return
    }
    attributes = assign({}, defaultAttributes, attributes)
    if (typeof attributes.expires === 'number') {
        attributes.expires = new Date(Date.now() + attributes.expires * 864e5)
    }
    if (attributes.expires) {
        attributes.expires = attributes.expires.toUTCString()
    }
    name = encodeURIComponent(name)
        .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
        .replace(/[()]/g, escape)
    var stringifiedAttributes = ''
    for (var attributeName in attributes) {
        if (!attributes[attributeName]) {
            continue
        }
        stringifiedAttributes += '; ' + attributeName
        if (attributes[attributeName] === true) {
            continue
        }
        // Considers RFC 6265 section 5.2:
        // ...
        // 3.  If the remaining unparsed-attributes contains a %x3B (";")
        //     character:
        // Consume the characters of the unparsed-attributes up to,
        // not including, the first %x3B (";") character.
        // ...
        stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]
    }
    return (document.cookie =
        name + '=' + converter.write(value, name) + stringifiedAttributes)
}

一行一行來(lái)看:

if (typeof document === 'undefined') {
    return
}

首先判斷是否有document對(duì)象,如果沒(méi)有則直接返回,這說(shuō)明js-cookie只能在瀏覽器環(huán)境下使用。

attributes = assign({}, defaultAttributes, attributes)

然后合并配置項(xiàng),將defaultAttributes和傳入的attributes合并,這里的assign大家直接理解為Object.assign就好了。

if (typeof attributes.expires === 'number') {
    attributes.expires = new Date(Date.now() + attributes.expires * 864e5)
}
if (attributes.expires) {
    attributes.expires = attributes.expires.toUTCString()
}

然后判斷expires是否是一個(gè)數(shù)字,如果是數(shù)字則將其轉(zhuǎn)換為一個(gè)Date對(duì)象;

這里的864e5是一個(gè)常量,結(jié)尾的e5代表后面加5個(gè)0,也就是86400000表示一天的毫秒數(shù)。

然后判斷expires是否存在,如果存在則將其轉(zhuǎn)換為UTC時(shí)間。

name = encodeURIComponent(name)
    .replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
    .replace(/[()]/g, escape)

這里對(duì)name進(jìn)行了編碼,然后將name中的%、(、)進(jìn)行了轉(zhuǎn)義。

escape是一個(gè)內(nèi)置函數(shù),它的作用是將一個(gè)字符串轉(zhuǎn)換為UTF-8編碼的字符串,這里的escape是將()轉(zhuǎn)換為%28、%29

參考:escape()

var stringifiedAttributes = ''
for (var attributeName in attributes) {
    if (!attributes[attributeName]) {
        continue
    }
    stringifiedAttributes += '; ' + attributeName
    if (attributes[attributeName] === true) {
        continue
    }
    // Considers RFC 6265 section 5.2:
    // ...
    // 3.  If the remaining unparsed-attributes contains a %x3B (";")
    //     character:
    // Consume the characters of the unparsed-attributes up to,
    // not including, the first %x3B (";") character.
    // ...
    stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]
}

這里是將attributes轉(zhuǎn)換為字符串,這里的stringifiedAttributes是一個(gè)字符串,最后的結(jié)果是這樣的:

stringifiedAttributes = '; path=/; expires=Wed, 21 Oct 2015 07:28:00 GMT'

最后將name、value、stringifiedAttributes拼接起來(lái),然后賦值給document.cookie。

get

function get(name) {
    if (typeof document === 'undefined' || (arguments.length && !name)) {
        return
    }
    // To prevent the for loop in the first place assign an empty array
    // in case there are no cookies at all.
    var cookies = document.cookie ? document.cookie.split('; ') : []
    var jar = {}
    for (var i = 0; i < cookies.length; i++) {
        var parts = cookies[i].split('=')
        var value = parts.slice(1).join('=')
        try {
            var found = decodeURIComponent(parts[0])
            jar[found] = converter.read(value, found)
            if (name === found) {
                break
            }
        } catch (e) {
        }
    }
    return name ? jar[name] : jar
}

get方法的實(shí)現(xiàn)比較簡(jiǎn)單,主要是解析document.cookie,然后將其轉(zhuǎn)換為一個(gè)對(duì)象,來(lái)逐行解析:

if (typeof document === 'undefined' || (arguments.length && !name)) {
    return
}

對(duì)比于set方法,這里多了一個(gè)(arguments.length && !name)的判斷,這里是防止傳入空字符串的name。

var cookies = document.cookie ? document.cookie.split('; ') : []

這里是將document.cookie分割為一個(gè)數(shù)組,每一項(xiàng)是一個(gè)cookie

var jar = {}
for (var i = 0; i < cookies.length; i++) {
    var parts = cookies[i].split('=')
    var value = parts.slice(1).join('=')
}

這一步是只要cookienamevalue,其他的一些額外附加信息都不需要。

try {
    var found = decodeURIComponent(parts[0])
    jar[found] = converter.read(value, found)
    if (name === found) {
        break
    }
} catch (e) {
}

這里是將name進(jìn)行了解碼,然后將namevalue存儲(chǔ)到jar對(duì)象中,如果傳入了name,則在找到對(duì)應(yīng)的name后就跳出循環(huán)。

return name ? jar[name] : jar

最后返回jar對(duì)象,如果傳入了name,則返回對(duì)應(yīng)的value,否則返回整個(gè)jar對(duì)象。

這里的核心是converter.read,這個(gè)方法是用來(lái)解析value的,這里的converter是一個(gè)對(duì)象,它有兩個(gè)方法:

/* eslint-disable no-var */
export default {
  read: function (value) {
    if (value[0] === '"') {
      value = value.slice(1, -1)
    }
    return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent)
  },
  write: function (value) {
    return encodeURIComponent(value).replace(
      /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,
      decodeURIComponent
    )
  }
}
/* eslint-enable no-var */

read方法是將value進(jìn)行解碼,write方法是將value進(jìn)行編碼。

remove

function remove(name, attributes) {
    set(
        name,
        '',
        assign({}, attributes, {
            expires: -1
        })
    )
}

remove方法就是使用set方法將value設(shè)置為空字符串,然后將expires設(shè)置為-1,這樣就相當(dāng)于刪除了cookie。

withAttributes & withConverter

Object.create({
    withAttributes: function (attributes) {
        return init(assign({}, defaultAttributes, attributes))
    },
    withConverter: function (converter) {
        return init(assign({}, defaultConverter, converter))
    }
})

這兩個(gè)方法就是用來(lái)設(shè)置defaultAttributesdefaultConverter的,這兩個(gè)對(duì)象是用來(lái)設(shè)置cookie的默認(rèn)屬性和默認(rèn)的converter

總結(jié)

通過(guò)學(xué)習(xí)js-cookie的源碼,我們可以了解到cookie的基本使用,如果想深入了解cookie,可以參考MDN。

同時(shí)我們也學(xué)會(huì)了很多字符串的處理方法,比如encodeURIComponent、decodeURIComponentsplit、join等等。

以上就是JS前端操作 Cookie源碼示例解析的詳細(xì)內(nèi)容,更多關(guān)于JS前端操作Cookie的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論