Vue踩坑記錄(一)——vue,data屬性爲何使用了_或$開頭卻會提示報錯?

咱們先來看一個簡單的例子:html

<template>
 <div class="hello">
    {{test}}
    {{_tttttttttt}}
    {{$tttttt}}
  </div>
</template>
<script>
import h222 from './h2'
export default {
  name: 'HelloWorld',
  data () {
    return {
      _tttttttttt: '__',
      $tttttt: '$$',
      test: 'test'
    }
  },
  mounted () {
    console.log(this)
  }
}
</script>

這麼一個簡單例子,可是vue卻會提示你報錯了,錯誤以下:vue

clipboard.png

從錯誤中咱們能夠發現報錯的緣由居然是$tttttt和_tttttttttt的變量是沒有定義。這是爲何呢?
咱們明明在data中定義了。
經過查看官網API說明,data中不要使用$和_開頭,由於在Vue內部也使用$和_做爲方法或屬性,這是爲了防止衝突。
那麼咱們就從源碼的角度來分析,咱們定義的變量爲何沒了呢??、ide

咱們都知道vue採用了ES的defineProperty來實現數據驅動視圖,以下:ui

Object.defineProperty(target, key) {
    enumerable: true,
    configurable: true,
    get: function() {
        // 這裏獲取數據
    },
    set: function() {
        // 這裏設置參數,通知更新視圖
    }
}

可若是僅僅是這樣的話,咱們在vue中是無法經過this.xxx來獲取變量的,而必須是經過this.$data.xxx。所以vue的變量都掛在在$data或_data上。this

因此vue內部還作了一層代理,以下spa

// target是vue實例,key爲_data,這樣就能經過訪問this.xxx = this._data.xxx了
function proxy (target, sourceKey, key) {
  sharedPropertyDefinition.get = function proxyGetter () {
    return this[sourceKey][key]
  };
  sharedPropertyDefinition.set = function proxySetter (val) {
    this[sourceKey][key] = val;
  };
  Object.defineProperty(target, key, sharedPropertyDefinition);
}

因此那麼咱們的變量爲何仍是不存在呢,那是由於vue作了一個檢測,檢測你的變量的開頭是否爲_或$,若是使用了那麼就不會使用代理了,
變量只會存在$data上或_data上。咱們來看下源碼:代理

function initData (vm) {
  var data = vm.$options.data;
  data = vm._data = typeof data === 'function'
    ? getData(data, vm)
    : data || {};
  if (!isPlainObject(data)) {
    data = {};
    process.env.NODE_ENV !== 'production' && warn(
      'data functions should return an object:\n' +
      'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
      vm
    );
  }
  // proxy data on instance
  var keys = Object.keys(data);
  var props = vm.$options.props;
  var methods = vm.$options.methods;
  var i = keys.length;
  while (i--) {
    var key = keys[i];
    if (process.env.NODE_ENV !== 'production') {
      if (methods && hasOwn(methods, key)) {
        warn(
          ("Method \"" + key + "\" has already been defined as a data property."),
          vm
        );
      }
    }
    if (props && hasOwn(props, key)) {
      process.env.NODE_ENV !== 'production' && warn(
        "The data property \"" + key + "\" is already declared as a prop. " +
        "Use prop default value instead.",
        vm
      );
    } else if (!isReserved(key)) {
        // 這邊處理代理,因此isReserved處理了是否要進行代理
      proxy(vm, "_data", key);
    }
  }
  // observe data
  observe(data, true /* asRootData */);

  function isReserved (str) {
      var c = (str + '').charCodeAt(0);
      return c === 0x24 || c === 0x5F // 這邊判斷chartCode是否爲_和$
   }
}

到這裏咱們就完成的解釋爲何沒法訪問了,因此通常不要使用_和$命名,若是真的要使用的話,那也行。
使用以下就不會報錯了。code

<template>
 <div class="hello">
    {{test}}
    {{_data._tttttttttt}}
    {{_data.$tttttt}}
    {{$data._tttttttttt}}
    {{$data.$tttttt}}
  </div>
</template>
<script>
import h222 from './h2'
export default {
  name: 'HelloWorld',
  data () {
    return {
      _tttttttttt: '__',
      $tttttt: '$$',
      test: 'test'
    }
  },
  mounted () {
    console.log(this.$data._tttttttttt)
    console.log(this.$data.$tttttt)
    console.log(this._data._tttttttttt)
    console.log(this._data.$tttttt)
  }
}

您的點贊是我繼續努力的動力,謝謝。component

相關文章
相關標籤/搜索