欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue數(shù)據(jù)初始化initState的實例詳解

 更新時間:2019年04月11日 08:55:16   作者:hfhan  
Vue 實例在建立的時候會運行一系列的初始化操作,而在這些初始化操作里面,和數(shù)據(jù)綁定關(guān)聯(lián)最大的是 initState。這篇文章主要介紹了vue數(shù)據(jù)初始化--initState,需要的朋友可以參考下

數(shù)據(jù)初始化

Vue 實例在建立的時候會運行一系列的初始化操作,而在這些初始化操作里面,和數(shù)據(jù)綁定關(guān)聯(lián)最大的是 initState。

首先,來看一下他的代碼:

function initState(vm) {
 vm._watchers = [];
 var opts = vm.$options;
 if(opts.props) {
  initProps(vm, opts.props); //初始化props
 }
 if(opts.methods) {
  initMethods(vm, opts.methods); //初始化methods
 }
 if(opts.data) {
  initData(vm); //初始化data
 } else {
  observe(vm._data = {}, true /* asRootData */ );
 }
 if(opts.computed) {
  initComputed(vm, opts.computed); //初始化computed
 }
 if(opts.watch && opts.watch !== nativeWatch) {
  initWatch(vm, opts.watch); //初始化watch
 }
}

在這么多的數(shù)據(jù)的初始化中,props、methods和data是比較簡單的(所以我就不詳細(xì)介紹了☺),而computed 和 watch則相對較難,邏輯較復(fù)雜,所以我下面主要講下computed 和 watch(以下代碼部分為簡化后的)。

initState里面主要是對vue實例中的 props, methods, data, computed 和 watch 數(shù)據(jù)進(jìn)行初始化。

在初始化props的時候(initProps),會遍歷props中的每個屬性,然后進(jìn)行類型驗證,數(shù)據(jù)監(jiān)測等(提供為props屬性賦值就拋出警告的鉤子函數(shù))。

在初始化methods的時候(initMethods),主要是監(jiān)測methods中的方法名是否合法。

在初始化data的時候(initData),會運行 observe 函數(shù)深度遍歷數(shù)據(jù)中的每一個屬性,進(jìn)行數(shù)據(jù)劫持。

在初始化computed的時候(initComputed),會監(jiān)測數(shù)據(jù)是否已經(jīng)存在data或props上,如果存在則拋出警告,否則調(diào)用defineComputed函數(shù),監(jiān)聽數(shù)據(jù),為組件中的屬性綁定getter及setter。如果computed中屬性的值是一個函數(shù),則默認(rèn)為屬性的getter函數(shù)。此外屬性的值還可以是一個對象,他只有三個有效字段set、get和cache,分別表示屬性的setter、getter和是否啟用緩存,其中g(shù)et是必須的,cache默認(rèn)為true。

function initComputed(vm, computed) {
 var watchers = vm._computedWatchers = Object.create(null);

 for(var key in computed) {
  var userDef = computed[key];
  var getter = typeof userDef === 'function' ? userDef : userDef.get;

  //創(chuàng)建一個計算屬性 watcher
  watchers[key] = new Watcher(
   vm,
   getter || noop,
   noop,
   computedWatcherOptions
  );

  if(!(key in vm)) {
   //如果定義的計算屬性不在組件實例上,對屬性進(jìn)行數(shù)據(jù)劫持
   //defineComputed 很重要,下面我們再說
   defineComputed(vm, key, userDef);
  } else {
   //如果定義的計算屬性在data和props有,拋出警告
  }
 }
}

在初始化watch的時候(initWatch),會調(diào)用vm.$watch函數(shù)為watch中的屬性綁定setter回調(diào)(如果組件中沒有該屬性則不能成功監(jiān)聽,屬性必須存在于props、data或computed中)。如果watch中屬性的值是一個函數(shù),則默認(rèn)為屬性的setter回調(diào)函數(shù),如果屬性的值是一個數(shù)組,則遍歷數(shù)組中的內(nèi)容,分別為屬性綁定回調(diào),此外屬性的值還可以是一個對象,此時,對象中的handler字段代表setter回調(diào)函數(shù),immediate代表是否立即先去執(zhí)行里面的handler方法,deep代表是否深度監(jiān)聽。

vm.$watch函數(shù)會直接使用Watcher構(gòu)建觀察者對象。watch中屬性的值作為watcher.cb存在,在觀察者update的時候,在watcher.run函數(shù)中執(zhí)行。想了解這一過程可以看我上一篇的 vue響應(yīng)式系統(tǒng)--observe、watcher、dep中關(guān)于Watcher的介紹。

function initWatch(vm, watch) {
 //遍歷watch,為每一個屬性創(chuàng)建偵聽器
 for(var key in watch) {
  var handler = watch[key];
  //如果屬性值是一個數(shù)組,則遍歷數(shù)組,為屬性創(chuàng)建多個偵聽器
  //createWatcher函數(shù)中封裝了vm.$watch,會在vm.$watch中創(chuàng)建偵聽器
  if(Array.isArray(handler)) {
   for(var i = 0; i < handler.length; i++) {
    createWatcher(vm, key, handler[i]);
   }
  } else {
   //為屬性創(chuàng)建偵聽器
   createWatcher(vm, key, handler);
  }
 }
}

function createWatcher(vm, expOrFn, handler, options) {
 //如果屬性值是一個對象,則取對象的handler屬性作為回調(diào)
 if(isPlainObject(handler)) {
  options = handler;
  handler = handler.handler;
 }
 //如果屬性值是一個字符串,則從組件實例上尋找
 if(typeof handler === 'string') {
  handler = vm[handler];
 }
 //為屬性創(chuàng)建偵聽器
 return vm.$watch(expOrFn, handler, options)
}

computed

computed本質(zhì)是一個惰性求值的觀察者,具有緩存性,只有當(dāng)依賴變化后,第一次訪問 computed 屬性,才會計算新的值

下面將圍繞這一句話來做解釋。

上面代碼中提到過,當(dāng)計算屬性中的數(shù)據(jù)存在與data和props中時,會被警告,也就是這種做法是錯誤的。所以一般的,我們都會直接在計算屬性中聲明數(shù)據(jù)。還是那個代碼片段中,如果定義的計算屬性不在組件實例上,會運行defineComputed函數(shù)對數(shù)據(jù)進(jìn)行數(shù)據(jù)劫持。下面我們來看下defineComputed函數(shù)中做了什么。

function defineComputed(target, key, userDef) {
 //是不是服務(wù)端渲染
 var shouldCache = !isServerRendering();
 //如果我們把計算屬性的值寫成一個函數(shù),這時函數(shù)默認(rèn)為計算屬性的get
 if(typeof userDef === 'function') {
  sharedPropertyDefinition.get = shouldCache ?
   //如果不是服務(wù)端渲染,則默認(rèn)使用緩存,設(shè)置get為createComputedGetter創(chuàng)建的緩存函數(shù)
   createComputedGetter(key) :
   //否則不使用緩存,直接設(shè)置get為userDef這個我們定義的函數(shù)
   userDef;
  //設(shè)置set為空函數(shù)
  sharedPropertyDefinition.set = noop;
 } else {
  //如果我們把計算屬性的值寫成一個對象,對象中可能包含set、get和cache三個字段
  sharedPropertyDefinition.get = userDef.get ?
   shouldCache && userDef.cache !== false ?
   //如果我們傳入了get字段,且不是服務(wù)端渲染,且cache不為false,設(shè)置get為createComputedGetter創(chuàng)建的緩存函數(shù)
   createComputedGetter(key) : 
   //如果我們傳入了get字段,但是是服務(wù)端渲染或者cache設(shè)為了false,設(shè)置get為userDef這個我們定義的函數(shù)
   userDef.get :
   //如果沒有傳入get字段,設(shè)置get為空函數(shù)
   noop;
  //設(shè)置set為我們傳入的傳入set字段或空函數(shù)
  sharedPropertyDefinition.set = userDef.set ?
   userDef.set :
   noop;
 }
 //雖然這里可以get、set都可以設(shè)置為空函數(shù)
 //但是在項目中,get為空函數(shù)對數(shù)據(jù)取值會報錯,set為空函數(shù)對數(shù)據(jù)賦值會報錯
 //而computed主要作用就是計算取值的,所以get字段是必須的
 //數(shù)據(jù)劫持
 Object.defineProperty(target, key, sharedPropertyDefinition);
}

在上一篇的 vue響應(yīng)式系統(tǒng)--observe、watcher、dep 中,我有關(guān)于Watcher的介紹中提到,計算屬性 watcher實例化的時候,會把options.lazy設(shè)置為true,這里是計算屬性惰性求值,且可緩存的關(guān)鍵,當(dāng)然前提是cache不為false。

cache不為false,會調(diào)用createComputedGetter函數(shù)創(chuàng)建計算屬性的getter函數(shù)computedGetter,

先來看一段代碼

function createComputedGetter(key) {
 return function computedGetter() {
  var watcher = this._computedWatchers && this._computedWatchers[key];
  if(watcher) {
   if(watcher.dirty) {
    //watcher.evaluate中更新watcher的值,并把watcher.dirty設(shè)置為false
    //這樣等下次依賴更新的時候才會把watcher.dirty設(shè)置為true,然后進(jìn)行取值的時候才會再次運行這個函數(shù)
    watcher.evaluate();
   }
   //依賴追蹤
   if(Dep.target) {
    watcher.depend();
   }
   //返回watcher的值
   return watcher.value
  }
 }
}
//對于計算屬性,當(dāng)取值計算屬性時,發(fā)現(xiàn)計算屬性的watcher的dirty是true
//說明數(shù)據(jù)不是最新的了,需要重新計算,這里就是重新計算計算屬性的值。
Watcher.prototype.evaluate = function evaluate() {
 this.value = this.get();
 this.dirty = false;
};
//當(dāng)一個依賴改變的時候,通知它update
Watcher.prototype.update = function update() {
 //三種watcher,只有計算屬性 watcher的lazy設(shè)置了true,表示啟用惰性求值
 if(this.lazy) {
  this.dirty = true;
 } else if(this.sync) {
  //標(biāo)記為同步計算的直接運行run,三大類型暫無,所以基本會走下面的queueWatcher
  this.run();
 } else {
  //將watcher推入觀察者隊列中,下一個tick時調(diào)用。
  //也就是數(shù)據(jù)變化不是立即就去更新的,而是異步批量去更新的
  queueWatcher(this);
 }
};

當(dāng)options.lazy設(shè)置為true之后(僅計算屬性watcher的options.lazy設(shè)置為true),每次依賴更新,都不會主動觸發(fā)run函數(shù),而是把watcher.dirty設(shè)置為true。這樣,當(dāng)對計算屬性進(jìn)行取值時,就會運行computedGetter函數(shù),computedGetter函數(shù)中有一個關(guān)于watcher.dirty的判斷,當(dāng)watcher.dirty為true時會運行watcher.evaluate進(jìn)行值的更新,并把watcher.dirty設(shè)置為false,這樣就完成了惰性求值的過程。后面只要依賴不更新,就不會運行update,就不會把watcher.dirty為true,那么再次取值的時候就不會運行watcher.evaluate進(jìn)行值的更新,從而達(dá)到了緩存的效果。

綜上,我們了解到cache不為false的時候,計算屬性都是惰性求值且具有緩存性的,而cache默認(rèn)是true,我們也大多使用這個默認(rèn)值,所以我們說 computed本質(zhì)是一個惰性求值的觀察者,具有緩存性,只有當(dāng)依賴變化后,第一次訪問 computed 屬性,才會計算新的值 。

總結(jié)

以上所述是小編給大家介紹的vue數(shù)據(jù)初始化initState的實例詳解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,請注明出處,謝謝!

相關(guān)文章

  • vue使用drag與drop實現(xiàn)拖拽的示例代碼

    vue使用drag與drop實現(xiàn)拖拽的示例代碼

    本篇文章主要介紹了vue使用drag與drop實現(xiàn)拖拽的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • Vuex的五大核心詳細(xì)講解

    Vuex的五大核心詳細(xì)講解

    這篇文章主要為大家介紹了vuex的五個核心概念和基本使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-09-09
  • vue.js 實現(xiàn)點擊按鈕動態(tài)添加li的方法

    vue.js 實現(xiàn)點擊按鈕動態(tài)添加li的方法

    今天小編就為大家分享一篇vue.js 實現(xiàn)點擊按鈕動態(tài)添加li的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-09-09
  • vue檢測對象和數(shù)組的變化分析

    vue檢測對象和數(shù)組的變化分析

    這篇文章給大家分享了vue檢測對象和數(shù)組的變化的相關(guān)知識點與實例代碼,有興趣的朋友參考下。
    2018-06-06
  • vue3+uniapp 上傳附件的操作代碼

    vue3+uniapp 上傳附件的操作代碼

    uni-file-picker搭配uni.uploadFile在使用問題上踩了不少坑,我至今還是沒辦法在不改uniapp源碼基礎(chǔ)上實現(xiàn)限制重復(fù)文件的上傳,這篇文章介紹vue3+uniapp 上傳附件的操作代碼,感興趣的朋友一起看看吧
    2024-01-01
  • element-ui中dialog彈窗關(guān)閉按鈕失效的解決

    element-ui中dialog彈窗關(guān)閉按鈕失效的解決

    這篇文章主要介紹了element-ui中dialog彈窗關(guān)閉按鈕失效的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • element用腳本自動化構(gòu)建新組件的實現(xiàn)示例

    element用腳本自動化構(gòu)建新組件的實現(xiàn)示例

    本文主要介紹了element-ui的用腳本自動化構(gòu)建新組件的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Vue實現(xiàn)渲染數(shù)據(jù)后控制滾動條位置(推薦)

    Vue實現(xiàn)渲染數(shù)據(jù)后控制滾動條位置(推薦)

    這篇文章主要介紹了Vue實現(xiàn)渲染數(shù)據(jù)后控制滾動條位置,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-12-12
  • django+vue實現(xiàn)注冊登錄的示例代碼

    django+vue實現(xiàn)注冊登錄的示例代碼

    這篇文章主要介紹了django+vue實現(xiàn)注冊登錄的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • 關(guān)于el-tooltip使用\n換行的情況顯示

    關(guān)于el-tooltip使用\n換行的情況顯示

    這篇文章主要介紹了關(guān)于el-tooltip使用\n換行的情況顯示,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-04-04

最新評論