用Object.defineProperty實現雙向綁定

Object.defineProperty也稱 “對象屬性攔截器”

攔截器不懂?(這可是個好東西,懂得話請跳過這一部分)

比如你平常用 Person.name就可以獲取到 Person的 name屬性的值對吧,但是如果我給該 name屬性設置個攔截器,那你獲取的可不一定是我 name屬性的值咯(嘻嘻嘻),因爲我可以在攔截器裏操作,並且返回給你任何值,比如下面這個例子,你永遠獲取不到 age的真實值,控制檯只能打印 ‘別質疑我的年齡,我18’。

  let Person = {
    name: 'besam-juajua',
    age: '18'
  }
  Object.defineProperty(Person, 'age', {
    enumerable: true,
    configurable: false,
    get () {
      return '別質疑我的年齡,我18'
    }
  })
  console.log(Person.age);

當然,除了 get,還有 set,defineProperty接收三個參數,第一個要攔截的對象,第二個要攔截的屬性,第三個是要攔截的操作(俗稱 “描述”,是一個對象來的),那麼可以攔截哪些操作呢?如下(一共有六個):

value: 值  // 給改屬性賦值

writable: true  // 該屬性是否可寫

enumerable: true,  // 該屬性是否可枚舉,不理解的話,你可以理解爲 “是否可for...in”來遍歷

configurable: false,  // 是否可重新配置

get: function (value) { // 當獲取該屬性時,自動調用該方法 }

set: function (value) { // 當設置該屬性時,自動調用該方法 }

相信你已經基本瞭解 defineProperty了,下面講下該例子的一個典型應用(實現數據雙向綁定):

試試吧!創建一個 id 爲 bindData 的輸入框,然後插入這片代碼(你可以在控制檯和input裏改變 Person.name的值,查看結果)

  // 創建一個將要雙向綁定的對象
  var Person = { name: '' }

  // input輸入每一個字符,都將其數據傳到Person,這就先實現了單向綁定
  $('#bindData').on('input',function(e){Person.name = e.target.value}); 
  
  // 在控制檯每改變一次Person.name,都會將新值傳到input輸入框
  Object.defineProperty(Person,'name',{ 
    enumerable: true,
    configurable: true,
    get: function(){return this._name||'besam-juajua'},
    set: function(value){
      this._name = value;
      $('#bindData').value = value;
      console.log("Person.name = " + Person.name)
      console.log("input = " + $('#bindData').val())
    }
  })

很簡單吧,關於 Object.defineProperty, 你需要注意:

不能 writable 和 (set、get) 同時存在,有前者不能有後者,有後者不能有前者,因爲同時存在的話,就互相矛盾了

關於 get 和 set 裏面,爲什麼要用 this._name , 不明白的話,看我下一篇博客。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章