最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript實(shí)現(xiàn)枚舉的幾種方法總結(jié)

 更新時(shí)間:2023年08月30日 08:23:40   作者:liangyue  
在前端開(kāi)發(fā)中,我們可能經(jīng)常需要用到枚舉,使用枚舉的好處是為了讓代碼的可讀性更強(qiáng),避免直接使用數(shù)字或未知的字符串,但是在JavaScript中,要自己實(shí)現(xiàn)一個(gè)枚舉功能,那么大家能想到多少種實(shí)現(xiàn)枚舉的方法呢,我將介紹幾種實(shí)現(xiàn)枚舉的好方法

基于普通對(duì)象

我們來(lái)考慮一個(gè)場(chǎng)景:T恤的尺寸:Small、Medium、Large三種類(lèi)型,那么我們使用普通對(duì)象的方式來(lái)實(shí)現(xiàn),代碼如下:

const Sizes = {
  Small: 'small',
  Medium: 'medium',
  Large: 'large',
}

基于這種方式實(shí)現(xiàn)一個(gè)枚舉是非常簡(jiǎn)單的,而且也足夠的清晰,此時(shí)Sizes就是一個(gè)基于JavaScript普通對(duì)象的枚舉,它有3個(gè)命名常量:Size.Small、Size.MediumSize.Large,我們可以通過(guò)Size.small來(lái)獲取對(duì)應(yīng)的枚舉值。

優(yōu)點(diǎn)

  • 簡(jiǎn)單:使用這種方式實(shí)現(xiàn)枚舉是非常簡(jiǎn)單,只需要定義一個(gè)帶有鍵和值的對(duì)象即可

缺點(diǎn)

  • 容易被外部修改

當(dāng)我們?cè)诰S護(hù)一個(gè)大型的代碼倉(cāng)庫(kù)時(shí),枚舉值可能會(huì)被意外更改,代碼如下:

const size1 = Sizes.Medium
const size2 = Sizes.Medium = 'foo' // Changed!
console.log(size1 === Sizes.Medium) // logs false

如代碼中所示,當(dāng)枚舉被修改后,之后的邏輯將會(huì)出現(xiàn)問(wèn)題,這也就是說(shuō),我們實(shí)現(xiàn)枚舉的時(shí)候需要考慮對(duì)象的值不能被修改

基于Symbol

我們也可以這樣實(shí)現(xiàn)一個(gè)枚舉:

const Sizes = {
  Small: Symbol('small'),
  Medium: Symbol('medium'),
  Large: Symbol('large'),
}
const mySize = Sizes.Large;
console.log(mySize === Sizes.Large); // true
console.log(mySize === Symbol('large')); // false

使用這種方式實(shí)現(xiàn)的枚舉看上去和機(jī)遇普通對(duì)象的方式類(lèi)似,只是把對(duì)象中的值修改成了Symbol類(lèi)型,那么這樣和剛才的方式又有什么不同呢?

優(yōu)點(diǎn)

  • 必須使用枚舉本身來(lái)進(jìn)行比較:也就是上面代碼中我們必須使用Sizes.Large來(lái)比較,再重新創(chuàng)建一個(gè)Symbol('large')對(duì)比的話(huà)則不相等,而對(duì)比第一種方法,只要字符串相同即為相同,這種對(duì)比方式更加嚴(yán)格了

缺點(diǎn)

  • 不能使用JSON.stringify,使用JSON.stringify會(huì)將Symbol轉(zhuǎn)為undefined、null或直接跳過(guò),代碼如下:
console.log(JSON.stringify(Sizes.Small)); // undefined
console.log(JSON.stringify([Sizes.Small])); // [null]
console.log(JSON.stringify({ size: Sizes.Small })) // {}
  • 容易被外部修改,這點(diǎn)與第一種方案的情況類(lèi)似,接下來(lái),我們將介紹如何能夠保證枚舉值不會(huì)被修改的方案

基于Object.freeze

使用Object.freeze可以使一個(gè)對(duì)象被凍結(jié):被凍結(jié)的對(duì)象不能再被更改:不能添加新的屬性,不能移除現(xiàn)有的屬性,不能更改它們的可枚舉性、可配置性、可寫(xiě)性或值,對(duì)象的原型也不能被重新指定。我們使用這種實(shí)現(xiàn)枚舉,代碼如下:

const Sizes = Object.freeze({
  Small: 'small',
  Medium: 'medium',
  Large: 'large',
})
const mySize = Sizes.Large;
Sizes.Large = '111'
console.log(mySize === Sizes.Large) // true

使用這種方式,就算去修改枚舉值也是無(wú)效的,如果在嚴(yán)格模式下,這種賦值的情況還會(huì)拋出錯(cuò)誤。

優(yōu)點(diǎn)

  • 有效防止枚舉值被修改

缺點(diǎn)

  • 當(dāng)拼寫(xiě)錯(cuò)誤時(shí),會(huì)直接返回undefined ,比如我們直接獲取Sizes.a,此時(shí)會(huì)返回undefined,這個(gè)問(wèn)題在前面的幾個(gè)方案中也是同樣的,我們?cè)陂_(kāi)發(fā)過(guò)程中,應(yīng)該是更希望拋出一個(gè)錯(cuò)誤,這樣在開(kāi)發(fā)階段更直接的發(fā)現(xiàn)問(wèn)題所在。于是,就有了下面一種方案。

基于Proxy

使用Proxy用于創(chuàng)建一個(gè)對(duì)象的代理,從而實(shí)現(xiàn)基本操作的攔截和自定義,Proxy并不會(huì)改變?cè)紝?duì)象的結(jié)構(gòu),而且我們可以實(shí)現(xiàn)如下兩個(gè)需求:

  • 訪(fǎng)問(wèn)不存在枚舉時(shí),拋出錯(cuò)誤
  • 修改枚舉對(duì)象屬性時(shí),拋出錯(cuò)誤

這樣,就可以同時(shí)滿(mǎn)足我們前面幾種方案遇到的問(wèn)題了,接下來(lái),我們封裝一個(gè)函數(shù),代碼如下:

function Enum(baseEnum) {
  return new Proxy(baseEnum, {
    get(target, name) {
      if (!baseEnum.hasOwnProperty(name)) {
        throw new Error(`"${name}" value does not exist in the enum`)
      }
      return baseEnum[name]
    },
    set(target, name, value) {
      throw new Error('Cannot add a new value to the enum')
    }
  })
}

這個(gè)函數(shù)中,我們傳入一個(gè)初始枚舉對(duì)象,當(dāng)我們?cè)L問(wèn)某個(gè)屬性的時(shí)候,如果沒(méi)有將會(huì)拋出錯(cuò)誤"${name}" value does not exist in the enum,當(dāng)我們修改值的時(shí)候,也會(huì)拋出一個(gè)錯(cuò)誤Cannot add a new value to the enum接下來(lái),我們使用這個(gè)函數(shù)包裝一下Sizes,代碼如下:

const Sizes = Enum({
  Small: 'small',
  Medium: 'medium',
  Large: 'large',
})
const mySize = Sizes.Large; // large
Sizes.Small = '1' // 拋出錯(cuò)誤: Cannot add a new value to the enum
console.log(Sizes.a) // 拋出錯(cuò)誤:"a" value does not exist in the enum

優(yōu)點(diǎn)

  • 枚舉值防止修改
  • 訪(fǎng)問(wèn)不存在的枚舉時(shí)會(huì)拋出錯(cuò)誤

缺點(diǎn)

  • 相對(duì)復(fù)雜,必須導(dǎo)入Enum函數(shù)

基于Class

另一個(gè)方法是基于JavaScript中的Class類(lèi)實(shí)現(xiàn)的,這個(gè)類(lèi)中包含一組靜態(tài)的字段,而每一個(gè)對(duì)應(yīng)的值本身又是這個(gè)實(shí)例,代碼如下:

class Sizes {
  static Small = new Sizes('small')
  static Medium = new Sizes('medium')
  static Large = new Sizes('large')
  #value
  constructor(value) {
    this.#value = value
  }
  toString() {
    return this.#value;
  }
}

每一個(gè)枚舉值都是一個(gè)Sizes實(shí)例,內(nèi)部有個(gè)私有屬性#value, 用來(lái)表示枚舉的原始值。我們舉幾個(gè)例子來(lái)看下使用這種方式實(shí)現(xiàn)的具有哪些特性:

const mySize = Sizes.Large;
console.log('mySize', Sizes.Large); // Sizes {}
console.log(mySize === Sizes.Large); // true
console.log(mySize === new Sizes('large')) // false
console.log('mySize string', Sizes.toString()) // large
console.log(mySize instanceof Sizes) // true

優(yōu)點(diǎn)

  • 可以通過(guò)instanceof來(lái)判斷是否是枚舉:上面例子中我們可以判斷出來(lái)mySize是一個(gè)枚舉
  • 這種方式枚舉的對(duì)比是基于實(shí)例的:上面例子中mySize === new Sizes('large') ,即使是相同的#value,也是不同的實(shí)例

缺點(diǎn)

  • 枚舉值可能會(huì)被意外修改
  • 訪(fǎng)問(wèn)不存在的枚舉時(shí)不會(huì)拋出錯(cuò)誤

總結(jié)

上面我們介紹了幾種在JavaScript中實(shí)現(xiàn)枚舉的方式,每種方式都有各自的優(yōu)缺點(diǎn),相比之下,我認(rèn)為:

  • Proxy方式更為靈活,可以按照自己的需求進(jìn)行更多的定制化;
  • 如果枚舉值用的較多,且項(xiàng)目較大,選擇Object.freeze方式,防止枚舉值被意外修改;
  • 如果您遇到的情況相對(duì)簡(jiǎn)單,使用基于普通對(duì)象的方式;

總之,我們最終的實(shí)現(xiàn)要盡量的簡(jiǎn)單,不要過(guò)度設(shè)計(jì),按照具體情況選擇合適的方式。

相關(guān)文章

最新評(píng)論

武清区| 雷波县| 宁德市| 怀安县| 玉环县| 宿松县| 苏尼特右旗| 鄯善县| 贵溪市| 秦安县| 廊坊市| 上栗县| 富锦市| 中超| 石屏县| 东方市| 通江县| 南漳县| 行唐县| 雅江县| 无锡市| 宣城市| 恭城| 汉阴县| 文山县| 富裕县| 兴安县| 辽阳县| 沅江市| 泰安市| 阿巴嘎旗| 乐山市| 山西省| 精河县| 宜宾市| 石家庄市| 从化市| 华亭县| 天气| 图们市| 城固县|