8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScriptのディスクリプタを使い、堅牢なオブジェクトやObservableなオブジェクトを作る

Posted at

ディスクリプタって?

たとえば、

let obj = { name: 'taro' }
Object.defineProperty(obj, 'age', {
  value: 100,
  writable: false
})

この第三引数をdescriptorという。

プロパティを細かく制御することができ、その制御モードを指示するオブジェクトのことをさす。

discriptorには2つタイプがある。

1. データディスクリプタ

value(, writable)をもつdiscriptor

{
    value: 123,         
    writable: false
    enumerable: false,
    configurable: false 
}

2. アクセサディスクリプタ

get, setをともにもつdiscriptor

{
    get: () => { return hoge },
    set: (val) => { hoge = val },
    enumerable: false,
    configurable: false
}

enumerableとconfigurableはともに持つことができる。
一方例えばvalueをもつときにget or setをもつとエラー。逆もしかり。

普通のattributes代入とどう違うか

obj.hoge = 120 はこれのショートハンド。
この場合は {value: 120, writable: true, configurable: true, enumerable: true} でセットされたことになる

何が嬉しいか

  • imutableな属性を作るなど堅牢性を増すことができる。
  • setterを使ってobservableなオブジェクトを作れる

では作ってみる

堅牢性をましたオブジェクトを作る

シンプルにwritableをfalseにする。

let obj = {}
Object.defineProperty(obj, 'age', {
  value: 100,
  writable: false,
  enumerable: false,   // false: for (let prop in obj) で age を列挙対象にしない
  configurable: false  // false: ディスクリプタを変更可能としない
})

console.log(obj.age) // 100
obj.age = 1000
console.log(obj.age) // 100 ... 変わらない

setterいじってもいいかもしれないが、 writable: false が楽

observableなオブジェクトを作る

(通知しすぎない(changedの検知), バリデーションなどは省略しました)

let obj = {}
let _age = 0
Object.defineProperty(obj, 'age', {
  get () { return _age },
  set (newValue) { 
    _age = newValue
    this.noticeObservers() // setしたらリスナーに通知
  },
  enumerable: false, 
  configurable: false
})

// observerの登録と通知
let listenerA = {}
listenerA.update = (observable) => {
  // 通知を受けたらなにかする
  console.log(`listerA received notification $(observable.age) from!`)
}
obj.observers = [listernA]

obj.noticeObservers = () => {
  this.observers.forEach((listener, _idx) => {
    listener.update(obj)
  })
}

関連

このProxyを使うとより柔軟にオブジェクトに対する処理に、任意の処理を挟み込める。

ref

なぜか definePropertyのページにdiscriptorの説明が載っている。

このあたりをより発展させたProxyについては https://aloerina01.github.io/blog/2017-03-14-1 こちらが詳しくて助かった。

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?