題目有個要求是若是傳入的對象是比較深的對象,也就是 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 } */