属性更改时Javascript Object.defineProperty set方法触发器

属性更改时Javascript Object.defineProperty set方法触发器,javascript,object,coffeescript,setter,ecmascript-5,Javascript,Object,Coffeescript,Setter,Ecmascript 5,以下面的(coffeescript)示例为例,它是一个具有details属性的Person类,而details属性又有自己的属性: class Person constructor: -> details = name: '' age: 0 Object.defineProperty this, 'details', enumerable: yes get: => details set: (value

以下面的(coffeescript)示例为例,它是一个具有details属性的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
显然,如果我只是将name和age定义为Person类的属性,我可以避免这个问题,但这只是一个示例


有什么简单的方法可以让my details set()方法在其属性发生更改时启动吗?

没有。至少不简单

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!"
是的,这真的很有效:

但老实说,这有点疯狂。你确定这就是你需要做的吗?也许你应该重新考虑你的方法