4

我们先来看一个简单的例子:

<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却会提示你报错了,错误如下:

clipboard.png

从错误中我们可以发现报错的原因竟然是$tttttt和_tttttttttt的变量是没有定义。这是为什么呢?
我们明明在data中定义了。
通过查看官网API说明,data中不要使用$和_开头,因为在Vue内部也使用$和_作为方法或属性,这是为了防止冲突。
那么我们就从源码的角度来分析,我们定义的变量为什么没了呢??、

我们都知道vue采用了ES的defineProperty来实现数据驱动视图,如下:

Object.defineProperty(target, key) {
    enumerable: true,
    configurable: true,
    get: function() {
        // 这里获取数据
    },
    set: function() {
        // 这里设置参数,通知更新视图
    }
}

可如果仅仅是这样的话,我们在vue中是没法通过this.xxx来获取变量的,而必须是通过this.$data.xxx。因此vue的变量都挂在在$data或_data上。

所以vue内部还做了一层代理,如下

// 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是否为_和$
   }
}

到这里我们就完成的解释为什么无法访问了,所以一般不要使用_和$命名,如果真的要使用的话,那也行。
使用如下就不会报错了。

<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)
  }
}

您的点赞是我继续努力的动力,谢谢。


DanielDemi
159 声望8 粉丝

开始前端之旅