點燈坊

失くすものさえない今が強くなるチャンスよ

使用 Object.freeze() 使 Object 實現 Immutable

Sam Xiao's Avatar 2020-02-03

ECMAScript 只有 Primitive 為 Immutable,Object 則為 Mutable;若要連 Object 也 Immutable,則要使用 Object.freeze()

Version

macOS Catalina 10.15.2
VS Code 1.41.1
Quokka 1.0.276
ECMAScript 2015

Object.freeze()

let book = {
  title: 'FP in JavaScript',
  price: 100,
  quantity: {
    Amazon: 10,
    eBay: 20
  }
}

Object.freeze(book)
book.price = 200
book.price // ?
book.quantity.Amazon = 30
book.quantity.Amazon // ?

ECMAScript 提供了 Object.freeze() 使 object 成為 immutable,唯只是 shallow freeze。

freeze000

第二層之後的 object 仍為 mutable。

deepFreeze()

let book = {
  title: 'FP in JavaScript',
  price: 100,
  quantity: {
    Amazon: 10,
    eBay: 20
  }
}

let isObject = val => val && typeof val === 'object'

let deepFreeze = obj => {
  if (!isObject(obj) || Object.isFrozen(obj)) return obj

  Object.freeze(obj)
  Object.keys(obj).forEach(x => deepFreeze(obj[x]))
}

deepFreeze(book)
book.price = 200
book.price // ?
book.quantity.Amazon = 30
book.quantity.Amazon // ?

第 10 行

let isObject = val => val && typeof val === 'object'

let deepFreeze = obj => {
  if (!isObject(obj) || Object.isFrozen(obj)) return obj

  Object.freeze(obj)
  Object.keys(obj).forEach(x => deepFreeze(obj[x]))
}

自行實作 deepFreeze(),若不是 object 或 object 已經被 freeze,則直接回傳 object。

除了使用 Object.freeze() 目前的 object 外,還使用 recursive 方式將第二層的 object 也 freeze。

freeze001

第二層之後的 object 已經是 immutable。

Conclusion

  • 雖然 ECMAScript 的 object 是 mutable,也可透過 Object.freeze() 自行實作 deepFreeze()  使 object 也能 immutable

Reference

Luis Atencio, Functional Programming in JavaScript
MDN, Object.freeze()
MDN, Object.isFrozen()