vue源码研究--Data为啥要写成函数?

大家在使用vue的时候,肯定有想过为什么 data 要写成函数,而不允许写成对象?
首先我们要想到:

  1. data是 Vue 实例上的一个属性。
  2. 对象是对于内存地址的引用。
  3. 函数有自己的作用域空间。
    vue 实例中的data是对象的写法,但是在组件中data是函数的写法,是因为写成函数,会有函数作用域的概念 ,是私有函数,只作用到当前组件中,不会影响到其它各个不同的组件。

第一点无可厚非,data属性附着于 Vue 实例上。

第二点,JS 的数据类型分为基本类型和引用类型,基本类型存储在栈内存中,引用类型存储在堆内存中,并且引用类型指向的是栈内存中的堆区地址。下面两个例子可以帮助你清晰地理解这句话。
基本数据类型赋值:

var a = 10;
var b = 10;
var c = a;
console.log(a === b); // true 
a ++ ;
console.log(a); // 11
console.log(c); // 10
a变化了 c没有变化

这段代码分别给 a、b 赋值 10,a 和 b 是全等的。然后用 a 来初始化 c,那么 c 的值也是 10。但 c 中的 10 与 a 中的是完全独立的,该值只是 a 中的值的一个副本,此后, 这两个变量可以参加任何操作而相互不受影响。具体位置如下示意图。
vue源码研究--Data为啥要写成函数?_第1张图片
引用类型赋值

var a = {};
var b = {};
var c = a;
console.log(a === b); // false
a.name = 'Marry';
a.say = () => console.log('Hi Marry!');
console.log(c.name); // 'Marry'
console.log(c.say()); // 'Hi Marry!'

上面这段代码。首先声明了a、b两个空对象,然后把 a 赋值给 c。因为对象是对栈内存的地址的引用,所以不同的对象的地址是不同的,所以他们不是全等的。接着给 a 新增加属性和方法,c 同样可以拥有此属性和方法,主要是因为 c 和 a 指向堆内存中的同一个地址。其关系图如下示意图所示。
vue源码研究--Data为啥要写成函数?_第2张图片
至于第三点,大多数有 JS 基础的同学应该都能理解,每个函数都有自己的作用域。

以上是对三个注意点的说明,那么接下来我们就以两个例子解释问题一:为什么 data 要写成函数,而不允许写成对象?
data 为对象示例代码

function MyCompnent() {}
MyCompnent.prototype.data = {
  age: 12
};
var JackMa = new MyCompnent();
var PonyMa = new MyCompnent();
console.log(JackMa.data.age === PonyMa.data.age); // true
JackMa.data.age = 13;
console.log('JackMa ' + JackMa.data.age + '岁;' + 'PonyMa ' + PonyMa.data.age + '岁'); 
// JackMa 13岁;PonyMa 13岁

上面的示例中,我们创建一个构造函数 MyCompnent,它充当的角色相当于 Vue,在他的原型属性上声明一个data属性,其实也相当于 Vue.$data。接着声明两个实例,改变其中一个实例,另外一个实例也会跟着改变,这个道理其实和引用类型赋值大同小异。
Tips:
关于构造函数的prototype继承原理,请参考详细解释:
面向对象的详细理解与继承方法对比
data 为函数的示例代码

function MyCompnent() {
  this.data = this.data();
}

MyCompnent.prototype.data = function() {
  return {
    age: 12
  }
};

var JackMa = new MyCompnent();
var PonyMa = new MyCompnent();

console.log(JackMa.data.age === PonyMa.data.age); // true

JackMa.data = {age: 13};

console.log('JackMa ' + JackMa.data.age + '岁;' + 'PonyMa ' + PonyMa.data.age + '岁');
// JackMa 13岁;PonyMa 12岁

上述代码模拟了 Vue 实例上的data为函数的时候,如果改变一个实例的data属性的值,那么不会影响到另外一个实例上的data的值。

Vue 里面data属性之所以不能写成对象的格式,是因为对象是对地址的引用,而不是独立存在的。如果一个.vue 文件有多个子组件共同接收一个变量的话,改变其中一个子组件内此变量的值,会影响其他组件的这个变量的值。如果写成函数的话,那么他们有一个作用域的概念在里面,相互隔阂,不受影响。

你可能感兴趣的:(vue)