真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

ES6使用新特性Proxy如何實現(xiàn)數(shù)據(jù)綁定功能

這篇文章主要講解了ES6使用新特性Proxy如何實現(xiàn)數(shù)據(jù)綁定功能,內(nèi)容清晰明了,對此有興趣的小伙伴可以學習一下,相信大家閱讀完之后會有幫助。

創(chuàng)新互聯(lián)于2013年成立,先為溧陽等服務建站,溧陽等地企業(yè),進行企業(yè)商務咨詢服務。為溧陽企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務解決您的所有建站問題。

作為一個前端開發(fā)者,曾踩了太多的“數(shù)據(jù)綁定”的坑。在早些時候,都是通過jQuery之類的工具手動完成這些功能,但是當數(shù)據(jù)量非常大的時候,這些手動的工作讓我非常痛苦。直到使用了VueJS,這些痛苦才得以終結(jié)。

VueJS的其中一個賣點,就是“數(shù)據(jù)綁定”。使用者無需關(guān)心數(shù)據(jù)是怎么綁定到dom上面的,只需要關(guān)注數(shù)據(jù)就好,因為VueJS已經(jīng)自動幫我們完成了這些工作。

這真的非常神奇,我不可救藥地愛上了VueJS,并且把它用到我自己的項目當中。隨著使用的深入,我更加想知道它深入的原理是什么。

VueJS是如何進行數(shù)據(jù)綁定的?

通過閱讀官方文檔,我看到了下面這段話:

把一個普通 Javascript 對象傳給 Vue 實例來作為它的 data 選項,Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉(zhuǎn)為 getter/setter。

關(guān)鍵詞是Object.definProperty,在MDN文檔里面是這么說的:

Object.defineProperty()方法直接定義一個對象的屬性,或者修改對象當中一個已經(jīng)存在的屬性,并返回這個對象。

讓我們寫個例子來測試一下它。

首先,建立一個鋼鐵俠對象并賦予他一些屬性:

let ironman = {
 name: 'Tony Stark',
 sex: 'male',
 age: '35'
}

現(xiàn)在我們使用Object.defineProperty()方法來對他的一些屬性進行修改,并且在控制臺把所修改的內(nèi)容輸出:

Object.defineProperty(ironman, 'age', {
 set (val) {
  console.log(`Set age to ${val}`)
  return val
 }
})

ironman.age = '48'
// --> Set age to 48

看起來挺完美的。如果把console.log('Set age to ${val}')改為element.innerHTML = val,是不是就意味著數(shù)據(jù)綁定已經(jīng)完成了呢?

讓我們再修改一下鋼鐵俠的屬性:

let ironman = {
 name: 'Tony Stark',
 sex: 'male',
 age: '35',
 hobbies: ['girl', 'money', 'game']
}

嗯……他就是一個花花公子。現(xiàn)在我想把一些“愛好”添加到他身上,并且在控制臺看到對應的輸出:

Object.defineProperty(ironman.hobbies, 'push', {
 value () {
  console.log(`Push ${arguments[0]} to ${this}`)
  this[this.length] = arguments[0]
 }
})

ironman.hobbies.push('wine')
console.log(ironman.hobbies)

// --> Push wine to girl,money,game
// --> [ 'girl', 'money', 'game', 'wine' ]

在此之前,我是使用get()方法去追蹤對象的屬性變化,但是對于一個數(shù)組,我們不能使用這個方法,而是使用value()方法來代替。雖然這招也靈,但是并非最好的辦法。有沒有更好的方法可以簡化這些追蹤對象或數(shù)組屬性變化的方法呢?

在ECMA2015,Proxy是一個不錯的選擇

什么是Proxy?在MDN文檔中是這么說的(誤):

Proxy可以理解成,在目標對象之前架設(shè)一層“攔截”,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機制,可以對外界的訪問進行過濾和改寫。

Proxy是ECMA2015的一個新特性,它非常強大,但我并不會討論太多關(guān)于它的東西,除了我們現(xiàn)在需要的一個。現(xiàn)在讓我們一起來新建一個Proxy實例:

let ironmanProxy = new Proxy(ironman, {
 set (target, property, value) {
  target[property] = value
  console.log('change....')
  return true
 }
})

ironmanProxy.age = '48'
console.log(ironman.age)

// --> change....
// --> 48

符合預期。那么對于數(shù)組呢?

let ironmanProxy = new Proxy(ironman.hobbies, {
 set (target, property, value) {
  target[property] = value
  console.log('change....')
  return true
 }
})

ironmanProxy.push('wine')
console.log(ironman.hobbies)

// --> change...
// --> change...
// --> [ 'girl', 'money', 'game', 'wine' ]

仍然符合預期!但是為什么輸出了兩次change...呢?因為每當我觸發(fā)push()方法的時候,這個數(shù)組的length屬性和body內(nèi)容都被修改了,所以會引起兩次變化。

實時數(shù)據(jù)綁定

解決了最核心的問題,可以考慮其他的問題了。

想象一下,我們有一個模板和數(shù)據(jù)對象:


Hello, my name is {{name}}, I enjoy eatting {{hobbies.food}}

let ironman = { name: 'Tony Stark', sex: 'male', age: '35', hobbies: { food: 'banana', drink: 'wine' } }

通過前面的代碼,我們知道如果想要追蹤一個對象的屬性變化,我們應該把這個屬性作為第一個參數(shù)傳入Proxy實例。讓我們一起來創(chuàng)建一個返回新的Proxy實例的函數(shù)吧!

function $setData (dataObj, fn) {
  let self = this
  let once = false
  let $d = new Proxy(dataObj, {
   set (target, property, value) {
    if (!once) {
     target[property] = value
     once = true
     /* Do something here */
    }
    return true
   }
  })
  fn($d)
 }

它可以通過以下的方式被使用:

$setData(dataObj, ($d) => {
 /* 
  * dataObj.someProps = something
  */
})

// 或者

$setData(dataObj.arrayProps, ($d) => {
 /* 
  * dataObj.push(something)
  */
})

除此之外,我們應該實現(xiàn)模板對數(shù)據(jù)對象的映射,這樣才能用Tony Stark來替換{{name}}

function replaceFun(str, data) {
  let self = this
  return str.replace(/{{([^{}]*)}}/g, (a, b) => {
   return data[b]
  })
 }

replaceFun('My name is {{name}}', { name: 'xxx' })
// --> My name is xxx

這個函數(shù)對于如{ name: 'xx', age: 18 }的單層屬性對象運行良好,但是對于如{ hobbies: { food: 'apple', drink: 'milk' } }這樣的多層屬性對象卻無能為力。舉個例子,如果模板關(guān)鍵字是{{hobbies.food}},那么replaceFun()函數(shù)就應該返回data['hobbies']['food']

為了解決這個問題,再來一個函數(shù):

function getObjProp (obj, propsName) {
  let propsArr = propsName.split('.')
  function rec(o, pName) {
   if (!o[pName] instanceof Array && o[pName] instanceof Object) {
    return rec(o[pName], propsArr.shift())
   }
   return o[pName]
  }
  return rec(obj, propsArr.shift())
 }

getObjProp({ data: { hobbies: { food: 'apple', drink: 'milk' } } }, 'hobbies.food')
// --> return { food: 'apple', drink: 'milk' }

最終的replaceFun()函數(shù)應該是下面這樣子的:

function replaceFun(str, data) {
  let self = this
  return str.replace(/{{([^{}]*)}}/g, (a, b) => {
   let r = self._getObjProp(data, b);
   console.log(a, b, r)
   if (typeof r === 'string' || typeof r === 'number') {
    return r
   } else {
    return self._getObjProp(r, b.split('.')[1])
   }
  })
 }

一個數(shù)據(jù)綁定的實例,叫做“Mog”

不為什么,就叫做“Mog”。

class Mog {
 constructor (options) {
  this.$data = options.data
  this.$el = options.el
  this.$tpl = options.template
  this._render(this.$tpl, this.$data)
 }

 $setData (dataObj, fn) {
  let self = this
  let once = false
  let $d = new Proxy(dataObj, {
   set (target, property, value) {
    if (!once) {
     target[property] = value
     once = true
     self._render(self.$tpl, self.$data)
    }
    return true
   }
  })
  fn($d)
 }

 _render (tplString, data) {
  document.querySelector(this.$el).innerHTML = this._replaceFun(tplString, data)
 }

 _replaceFun(str, data) {
  let self = this
  return str.replace(/{{([^{}]*)}}/g, (a, b) => {
   let r = self._getObjProp(data, b);
   console.log(a, b, r)
   if (typeof r === 'string' || typeof r === 'number') {
    return r
   } else {
    return self._getObjProp(r, b.split('.')[1])
   }
  })
 }

 _getObjProp (obj, propsName) {
  let propsArr = propsName.split('.')
  function rec(o, pName) {
   if (!o[pName] instanceof Array && o[pName] instanceof Object) {
    return rec(o[pName], propsArr.shift())
   }
   return o[pName]
  }
  return rec(obj, propsArr.shift())
 }

}

使用:



  

Hello everyone, my name is {{name}}, I am a mini {{lang}} framework for just {{work}}. I can bind data from {{supports.0}}, {{supports.1}} and {{supports.2}}. What's more, I was created by {{info.author}}, and was written in {{info.jsVersion}}. My motto is "{{motto}}".

Motto:


let template = document.querySelector('#app').innerHTML

let mog = new Mog({
 template: template,
 el: '#app',
 data: {
  name: 'mog',
  lang: 'javascript',
  work: 'data binding',
  supports: ['String', 'Array', 'Object'],
  info: {
   author: 'Jrain',
   jsVersion: 'Ecma2015'
  },
  motto: 'Every dog has his day'
 }
})

document.querySelector('#set-motto').oninput = (e) => {
 mog.$setData(mog.$data, ($d) => {
  $d.motto = e.target.value
 })
}

你可以在這里進行在線體驗。

后記

Mog僅僅是一個用于學習數(shù)據(jù)綁定的實驗性質(zhì)的項目,代碼仍然不夠優(yōu)雅,功能也不夠豐富。但是這個小玩具讓我學習了很多。如果你對它有興趣,歡迎到這里把項目fork走,并且加入一些你的想法。

看完上述內(nèi)容,是不是對ES6使用新特性Proxy如何實現(xiàn)數(shù)據(jù)綁定功能有進一步的了解,如果還想學習更多內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


新聞名稱:ES6使用新特性Proxy如何實現(xiàn)數(shù)據(jù)綁定功能
文章起源:http://weahome.cn/article/jgjedp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部