Javascript Object.defineProperty установить метод триггера на изменение свойства

Возьмем следующий (coffeescript) пример класса Person со свойством details, которое, в свою очередь, имеет свои собственные свойства:

class Person
  constructor: ->
    details =
      name: ''
      age: 0

    Object.defineProperty this, 'details',
      enumerable: yes
      get: => details
      set: (value) =>
        console.log 'set details:', value
        details = value

p = new Person

# does NOT trigger details set()
p.details.name = 'Simon'

# DOES trigger details set(), but takes a bit of effort...
details = p.details
details.name = 'Someone else'
p.details = details

Очевидно, что если бы я просто определил имя и возраст как свойства класса Person, я мог бы избежать этой проблемы, но это всего лишь пример.

Есть ли какой-нибудь простой способ заставить мой метод set() срабатывать при изменении его свойств?

1 ответ

На самом деле, нет. По крайней мере, не просто.

p это совершенно другой объект, чем p.details, Изменение p.details ничего не меняет p совсем. Так что не получу сообщение.

Что вам нужно сделать, это установить некоторый код, который заставляет объект details отправлять сообщение своему родителю при изменении его собственных свойств. Что также означает, что он должен знать, кто его родитель.

class Person
  constructor: ->
    details =
      name: ''
      age: 0

    Object.defineProperty this, 'details',
      enumerable: yes
      get: -> details
      set: (value) ->
        console.log 'set details:', value
        details = value

        # set parent object to tell when something changes
        value._parent = this

        # create a name setter, which tells it's parent when it changes.
        Object.defineProperty details, 'name',
          enumerable: yes
          get: -> @_name
          set: (value) ->
            @_parent.didUpdateDetails()

     # trigger setter to install hook
     @details = details

   didUpdateDetails: ->
     console.log 'Updated details!'

p = new Person
p.details.name = 'Alex'
# logs: "Updated details!"

И да, это действительно работает: http://jsfiddle.net/PkyaU/1/

Но, честно говоря, это немного безумие. Вы уверены, что это то, что вам нужно сделать? Может быть, вам следует пересмотреть свой подход.

Другие вопросы по тегам