题目有个要求是若是传入的对象是比较深的对象,也就是 value 能够能是另一个新的对象,也是要给那个对象的属性加上 getter 和 setter 的,个人作法就是判断每个值是不是对象,而后在作一次递归处理。github
each(obj) { Object.keys(obj).forEach(key => { // 若是值是一个对象的话 if (Object.prototype.toString.call(obj[key]) === '[object Object]') { // 递归自身 this.each(obj[key]) } else { this.convert(key, obj[key]) } }) }
这里用了Object.prototype.toString.call()
来判断值是什么类型,由于使用typeof
的话,object、array 和 null 都会返回 object,不是我想要的结果。json
题目还有另一个要求就是实现$watch
的功能,用过 Vue 的同窗都知道,咱们能够用这个函数去监听一个值的变化,而且传入一个回调函数,若是值发生变话的话,就执行回调函数。app
在constructor
中添加一个用来存储回调函数的变量:函数
... this.watchProperties = {} ...
实现$watch
和emit
函数:this
存储 watch 的回调函数作法我是用一个对象去处理的,key 为属性名,value 则是回调函数。prototype
$watch(name, fn) { this.watchProperties[name] = fn } emit(name, val) { if (this.watchProperties[name] && typeof this.watchProperties[name] === 'function') { this.watchProperties[name](val) } }
在convert
中添加:code
convert(key, value) { ... Object.defineProperty(this.setData || this.data, key, { ... set: function (newValue) { ... // 调用 emit 执行 watchProperties 里的回调函数 // key 为属性名 // newValue 为新设置的值 that.emit(key, newValue) ... } }) }
最后一步,暴露$watch
方法:server
constructor(json) { ... return { ... // 这里要注意,修改一下上下文的环境 $watch: this.$watch.bind(this) } }
这里须要使用bind
去修改执行的时候上下的环境,不然没法访问watchProperties
。对象
$watch
函数不可以监听比较深的对象的属性。
新建一个示例的时候,若是传入一个深对象,会被打平:
let app = new Observer({ name: { a: 1, b: 2 } }) console.log(app.data) // 会输出 /* [object Object] { a: 1, b: 2 } */