Vue中計(jì)算屬性、方法與偵聽屬性的區(qū)別剂碴?

總結(jié):

??1. 計(jì)算屬性computed在使用時把将,一定要注意,函數(shù)里面的變量都會被監(jiān)聽忆矛,只要里面的某一個值變動察蹲,便會將整個函數(shù)執(zhí)行一遍。 而 watch 只是監(jiān)聽某一個值催训,若是監(jiān)聽的值里面也有很多變量洽议,也會全部監(jiān)聽
??2. 計(jì)算后的屬性可不在 data 中定義,如果定義會報錯漫拭,因?yàn)閷?yīng)的computed作為計(jì)算屬性定義并返回對應(yīng)的結(jié)果給這個變量,變量不可被重復(fù)定義和賦值亚兄。 而 watch 監(jiān)聽 data 中定義的變量變化

computed特性
1.是計(jì)算值,
2.應(yīng)用:就是簡化tempalte里面{{}}計(jì)算和處理props或$emit的傳值
3.具有緩存性嫂侍,頁面重新渲染值不變化,計(jì)算屬性會立即返回之前的計(jì)算結(jié)果儿捧,而不必再次執(zhí)行函數(shù)

watch特性
1.是觀察的動作荚坞,
2.應(yīng)用:監(jiān)聽props挑宠,$emit或本組件的值執(zhí)行異步操作
3.無緩存性,頁面重新渲染時值不變化也會執(zhí)行

接下來介紹下 各自的方法:

1. 計(jì)算屬性 computed

在一個計(jì)算屬性里可以完成各種復(fù)雜的邏輯颓影,包括運(yùn)算各淀、函數(shù)調(diào)用等,只要最終返回一個結(jié)果就可以诡挂。

  <div id="example">
        <p>Original message: "{{ message }}"</p>
        <p>Computed reversed message: "{{ reversedMessage }}"</p> // 我們把復(fù)雜處理放在了計(jì)算屬性里面了
    </div>
var vm = new Vue({
    el: '#example',
    data: {
        message: 'Hello'
    },
    computed: {
        reversedMessage: function () {
            // `this` 指向 vm 實(shí)例
            return this.message.split('').reverse().join('')
        }
    }
});

結(jié)果:
? ? ? ?Original message: "Hello"
??Computed reversed message: "olleH"

計(jì)算屬性還可以依賴多個Vue 實(shí)例的數(shù)據(jù)碎浇,只要其中任一數(shù)據(jù)變化,計(jì)算屬性就會重新執(zhí)行璃俗,視圖也會更新奴璃。

每一個計(jì)算屬性都包含一個getter和一個setter ,我們上面的兩個示例都是計(jì)算屬性的默認(rèn)用法城豁, 只是利用了getter 來讀取苟穆。

在你需要時,也可以提供一個setter 函數(shù)唱星, 當(dāng)手動修改計(jì)算屬性的值就像修改一個普通數(shù)據(jù)那樣時雳旅,就會觸發(fā)setter 函數(shù),執(zhí)行一些自定義的操作间聊,例如:

    <div id="demo">
        <p> {{ fullName }} </p>
        <input type="text" v-model="fullName">
        <input type="text" v-model="firstName">
        <input type="text" v-model="lastName">
    </div>
    <script>
        var vm = new Vue({
            el: '#demo',
            data: {
                firstName: 'zhang',
                lastName: 'san'
            },
            computed: {
                fullName: {
                    //getter 方法
                    get(){
                        console.log('computed getter...')
                        return this.firstName + ' ' + this.lastName
                    },
                    //setter 方法
                    set(newValue){
                        console.log('computed setter...')
                        var names = newValue.split(' ')
                        this.firstName = names[0]
                        this.lastName = names[names.length - 1]
                        return this.firstName + ' ' + this.lastName
                    }
                
                }
            },
            updated () {
                console.log('updated')
            }
        })
    </script>

我們可以看到攒盈,input 是直接綁 v-model="fullName",如果我們這里直接修改了fullName的值哎榴,那么就會觸發(fā)setter型豁,同時也會觸發(fā)getter以及updated函數(shù)僵蛛。其執(zhí)行順序是setter -> getter -> updated,如下:

console.log('computed setter...')
console.log('computed getter...')
console.log('updated')

注意:并不是觸發(fā)了setter也就會觸發(fā)getter偷遗,他們兩個是相互獨(dú)立的墩瞳。我們這里修改了fullName會觸發(fā)getter是因?yàn)閟etter函數(shù)里有改變firstName 和 lastName 值的代碼。

2. 方法

除了使用計(jì)算屬性外氏豌,我們也可以通過在表達(dá)式中調(diào)用方法來達(dá)到同樣的效果喉酌,如:

  <div>{{reverseTitle()}}</div>
methods: {
  reverseTitle: function () {
    return this.title.split('').reverse().join('')
  }
}

我們可以將同一函數(shù)定義為一個方法而不是一個計(jì)算屬性,兩種方式的最終結(jié)果確實(shí)是完全相同的泵喘。只是一個使用reverseTitle()取值泪电,一個使用reverseTitle取值。

然而纪铺,不同的是計(jì)算屬性是基于它們的依賴進(jìn)行緩存的相速。計(jì)算屬性只有在它的相關(guān)依賴發(fā)生改變時才會重新求值。

這就意味著只要 title還沒有發(fā)生改變鲜锚,多次訪問 reverseTitle計(jì)算屬性會立即返回之前的計(jì)算結(jié)果突诬,而不必再次執(zhí)行函數(shù)。

3. 偵聽屬性 watch

watch監(jiān)控自身屬性變化:

   new Vue({
        el: '#app',
        data: {
            firstName: 'hello',
            lastName: 'vue',
            fullName: 'hello.ve'
        },
        watch: {
            'firstName': function(newval, oldval) {
                // console.log(newval,oldval);
                this.fullName = this.firstName + this.lastName;
            },
            'lastName': function(newval, oldval) {
                // console.log(newval,oldval);
                this.fullName = this.firstName + this.lastName;
            }
        }
    });

watch監(jiān)控路由對象:

    new Vue({
        el: '#app',
        router: router, //開啟路由對象
        watch: {
            '$route': function(newroute, oldroute) {
                console.log(newroute, oldroute);
                //可以在這個函數(shù)中獲取到當(dāng)前的路由規(guī)則字符串是什么
                //那么就可以針對一些特定的頁面做一些特定的處理
            }
        }
    })

watch監(jiān)聽對象的單個屬性:
watch如果想要監(jiān)聽對象的單個屬性的變化,必須用computed作為中間件轉(zhuǎn)化,因?yàn)閏omputed可以取到對應(yīng)的屬性值芜繁。

data(){
      return{
        'first':{
          second:0
        }
      }
    },
    computed:{
      secondChange(){
        return this.first.second
      }
    },
    watch:{
      secondChange(){
        console.log('second屬性值變化了')
      }
    },

簡單實(shí)現(xiàn) computedwatch

公共類

function defineReactive(data, key, val, fn) {
      let subs = [] // 新增
      Object.defineProperty(data, key, {
        configurable: true,
        enumerable: true,
        get: function() {
          // 新增
       if (data.$target) {
        subs.push(data.$target)
      }
      return val
     },
     set: function(newVal) {
      if (newVal === val) return
      fn && fn(newVal)
      // 新增
      if (subs.length) {
        // 用 setTimeout 因?yàn)榇藭r this.data 還沒更新
        setTimeout(() => {
          subs.forEach(sub => sub())
        }, 0)
      }
      val = newVal
    },
   })
 }

computed實(shí)現(xiàn)

function computed(ctx, obj) {
  let keys = Object.keys(obj)
  let dataKeys = Object.keys(ctx.data)
  dataKeys.forEach(dataKey => {
    defineReactive(ctx.data, dataKey, ctx.data[dataKey])
  })
  let firstComputedObj = keys.reduce((prev, next) => {
    ctx.data.$target = function() {
      ctx.setData({ [next]: obj[next].call(ctx) })
    }
    prev[next] = obj[next].call(ctx)
    ctx.data.$target = null
    return prev
  }, {})
  ctx.setData(firstComputedObj)
}

watch實(shí)現(xiàn)

function watch(ctx, obj) {
  Object.keys(obj).forEach(key => {
    defineReactive(ctx.data, key, ctx.data[key], function(value) {
      obj[key].call(ctx, value)
    })
  })
}

參考:Vue的computed和watch的細(xì)節(jié)全面分析kai

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末旺隙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子骏令,更是在濱河造成了極大的恐慌蔬捷,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榔袋,死亡現(xiàn)場離奇詭異周拐,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)凰兑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門妥粟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吏够,你說我怎么就攤上這事勾给。” “怎么了稿饰?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵锦秒,是天一觀的道長。 經(jīng)常有香客問我喉镰,道長旅择,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任侣姆,我火速辦了婚禮生真,結(jié)果婚禮上沉噩,老公的妹妹穿的比我還像新娘。我一直安慰自己柱蟀,他們只是感情好川蒙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著长已,像睡著了一般畜眨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上术瓮,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天康聂,我揣著相機(jī)與錄音,去河邊找鬼胞四。 笑死恬汁,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的辜伟。 我是一名探鬼主播氓侧,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼导狡!你這毒婦竟也來了约巷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤烘豌,失蹤者是張志新(化名)和其女友劉穎载庭,沒想到半個月后看彼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體廊佩,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年靖榕,在試婚紗的時候發(fā)現(xiàn)自己被綠了标锄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡茁计,死狀恐怖料皇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情星压,我是刑警寧澤践剂,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站娜膘,受9級特大地震影響逊脯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜竣贪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一军洼、第九天 我趴在偏房一處隱蔽的房頂上張望巩螃。 院中可真熱鬧,春花似錦匕争、人聲如沸避乏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拍皮。三九已至,卻和暖如春跑杭,著一層夾襖步出監(jiān)牢的瞬間春缕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工艘蹋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留锄贼,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓女阀,卻偏偏與公主長得像宅荤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子浸策,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容