首頁 >web前端 >前端問答 >vue元件中data為啥是函數

vue元件中data為啥是函數

青灯夜游
青灯夜游原創
2022-12-01 19:46:2911807瀏覽

原因:防止多個元件實例物件之間共用一個data,產生資料污染;採用函數的形式,initData時會將其作為工廠函數都會傳回全新data物件。當將元件中的data寫成一個函數,資料以函數傳回值形式定義,這樣每復用一次元件,就會傳回一份新的data,擁有自己的作用域,類似於為每個元件實例建立一個私有的資料空間,讓各個元件實例維護各自的資料。

vue元件中data為啥是函數

本教學操作環境:windows7系統、vue3版,DELL G3電腦。

一、實例和元件定義data的區別

vue實例的時候定義data屬性既可以是一個對象,也可以是一個函數

const app = new Vue({
    el:"#app",
    // 对象格式
    data:{
        foo:"foo"
    },
    // 函数格式
    data(){
        return {
             foo:"foo"
        }
    }
})

元件中定義data屬性,只能是一個函數

如果為元件data直接定義為一個物件

Vue.component('component1',{
    template:`<div>组件</div>`,
    data:{
        foo:"foo"
    }})

則會得到警告訊息

vue元件中data為啥是函數

警告說明:傳回的data應該是一個函數在每一個元件實例中

二、元件data定義函數與物件的差異

上面講到元件data必須是函數,不知道大家有沒有思考過這是為什麼呢?

在我們定義好一個元件的時候,vue最後都會透過Vue.extend()構成元件實例

這裡我們模仿元件建構函數,定義data屬性,採用物件的形式

function Component(){
 
}
Component.prototype.data = {
	count : 0
}

建立兩個元件實例

const componentA = new Component()
const componentB = new Component()

修改componentA元件data屬性的值,componentB中的值也發生了改變

console.log(componentB.data.count)  // 0
componentA.data.count = 1
console.log(componentB.data.count)  // 1

產生這樣的原因這是兩者共用了同一個記憶體位址,componentA修改的內容,同樣對componentB產生了影響。 【學習影片分享:vue影片教學web前端影片

#如果我們採用函數的形式,則不會出現這種情況(函數傳回的對象記憶體位址並不相同)

function Component(){
this.data = this.data()
}
Component.prototype.data = function (){
    return {
   count : 0
    }
}

修改componentA元件data屬性的值,componentB中的值不受影響

console.log(componentB.data.count)  // 0
componentA.data.count = 1
console.log(componentB.data.count)  // 0

vue元件可能會有很多個實例,採用函數傳回一個全新data形式,使每個實例物件的資料不會受到其他實例物件資料的污染

三、原理分析

首先可以看看vue初始化data的程式碼,data的定義可以是函數也可以是物件

原始碼位置:/vue-dev/src/core/instance/state.js

function initData (vm: Component) {
  let data = vm.$options.data
  data = vm._data = typeof data === &#39;function&#39;
    ? getData(data, vm)
    : data || {}
    ...
}

data既能是object也能是function,那為什麼還會出現上文警告呢?

別急,繼續看下文

元件在建立的時候,會進行選項的合併

原始碼位置:/vue-dev/src/core/ util/options.js

自訂元件會進入mergeOptions進行選項合併

Vue.prototype._init = function (options?: Object) {
    ...
    // merge options
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
    ...
  }

定義data會進行資料校驗

原始碼位置:/ vue-dev/src/core/instance/init.js

這時候vm實例為undefined,進入if判斷,若data類型不是function,則出現警告提示

strats.data = function (
  parentVal: any,
  childVal: any,
  vm?: Component
): ?Function {
  if (!vm) {
    if (childVal && typeof childVal !== "function") {
      process.env.NODE_ENV !== "production" &&
        warn(
          &#39;The "data" option should be a function &#39; +
            "that returns a per-instance value in component " +
            "definitions.",
          vm
        );
      return parentVal;
    }
    return mergeDataOrFn(parentVal, childVal);
  }
  return mergeDataOrFn(parentVal, childVal, vm);
};

四、結論

根實例物件data可以是物件也可以是函數(根實例是單例),不會產生資料污染情況

元件實例物件data必須為函數,目的是為了防止多個元件實例物件之間共用一個data,產生資料污染。採用函數的形式,initData時會將其作為工廠函數都會傳回全新data物件

說明:

  • ##vue中元件是用來復用的,為了防止data復用,將其定義為函數。

  • vue元件中的data資料都應該是互相隔離,互不影響的,元件每復用一次,data資料就應該被複製一次,之後,當某處複用的地方元件內data資料改變時,其他複用地方元件的data資料不受影響,就需要透過data函數傳回一個物件作為元件的狀態。

  • 當我們將元件中的data寫成一個函數,資料以函數傳回值形式定義,這樣每複用一次元件,就會傳回一份新的data,擁有自己的作用域,類似於為每個元件實例建立一個私有的資料空間,讓各個元件實例維護各自的資料。

  • 當我們元件的date單純的寫成物件形式,這些實例用的是同一個建構函數,由於JavaScript的特性所導致,所有的元件實例共用了一個data,就會造成一個變了全都會變的結果。

(學習影片分享:web前端開發程式設計基礎影片

以上是vue元件中data為啥是函數的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn