vue中子组件的beforeCreate钩子函数中读取父组件传入的数据出现报错

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <meta name="renderer" content="webkit">
  <title>父子组件生命周期</title>
</head>
<body>
  <div id="app">
    <p>{{parentData}}</p>
    <child message="hello子组件"></child>
  </div>
  <script src="https://cdn.bootcss.com/vue/2.5.15/vue.js"></script>
  <script>
    var app = new Vue({
      el: '#app',
      data: {
        parentData: '父组件数据',
      },
      beforeCreate() {
        console.log(`Parent--beforeCreate ${this.parentData} ${this.$el}`);
      },
      created() {
        console.log(`Parent--created ${this.parentData} ${this.$el}`);
      },
      components: {
        child: {
          template: `<div><p>{{message}}</p> <p>{{childrenData}}</p></div>`,
          props: {
            message: {
              type: String
            }
          },
          data: function () {
            return {
              childrenData: '子组件数据'
            }
          },
          beforeCreate() {
            console.log(this);
            console.log(`Child--beforeCreate ${this.message} ${this.childrenData} ${this.$el}`);
          },
          created() {
            console.log(`Child--created ${this.message} ${this.childrenData} ${this.$el}`);
          },
        }
      }
    })
  </script>
</body>

下面是输出
图片描述
子组件在beforeCreate中读取外部的传入的变量时报错了,但是令我疑惑的是,上面可以输出this的值,如果message没有绑定到子组件上,最多就是输出undefined值,而不应该报错。
难道是vue在内部规定了子组件在beforeCreate的钩子函数中不能读取外部传入的数据,否则报错?

阅读 3.7k
2 个回答

确实,按照正常情况来讲的,当this为object时,this.message是绝对不会报错的。

然鹅js不会欺骗你,那么这个锅只能让vue来背了。

你可以点击控制台报错的这一行,查看抛出错误的vue代码,也就是vue.esm.js?a026:3297:
at VueComponent.proxyGetter [as trigger] (vue.esm.js?a026:3297)

然后你会发现,代码大概是这样的:

var sharedPropertyDefinition = {
  enumerable: true,
  configurable: true,
  get: noop,
  set: noop
};

function proxy (target, sourceKey, key) {
  sharedPropertyDefinition.get = function proxyGetter () {
    return this[sourceKey][key] // 是这里报错了 sourceKey为_props, key为message
  };
  sharedPropertyDefinition.set = function proxySetter (val) {
    this[sourceKey][key] = val;
  };
  Object.defineProperty(target, key, sharedPropertyDefinition);
}

重点在于return this[sourceKey][key]

实际上this.message调用的并不是vue实例对象下的message属性,而是this._props.message
this._props在此时(beforeCreate)是undefined的。
这跟vue的生命周期有关,可以看这个图:https://cn.vuejs.org/images/l...

And,如果你在created钩子中console.log(this),你会发现this下是会有message属性的...(也有_props.message)。

是因为上面贴出的代码中有这一段:Object.defineProperty(target, key, sharedPropertyDefinition);
target是当前vue实例,key是message这一类的props。
( vue用了definePropertythis.message指向了this._props.message。)

所以,我们还可以做一个试验:

  created() {
    console.log(this._props) // object
    console.log(this.message, 11)  // 'message content'
    delete this._props.message
    console.log(this.message, 22) // undefined
  }
因为vue的数据劫持机制
在beforeCreate钩子中访问 this.message 实际上调用了
this.message的get函数 而在get函数中vue返回的是 this['_props']['message']
显然这个时候 this['_props'] 为undefined 这就是报错原因.

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题