前言:
工作中我们通过百度和官方文档很容易就知道一个语法怎么使用,但是你知道其中的原理吗?为什么要用这种方式?下面我们看看一些前端同学面试vue中可能经常被问及的问题。
VUE常见的问题
问题1、vue的
data
为什么要写成函数,而不允许写成对象?
可能从你接触vue你就是这样写的,但你是不是从未思考过为什么data是通过函数返回一个对象,为什么不直接写一个对象呢?带着这个问题往下看。
想要理解这个问题,首先要知道以下三个知识点:
data
是Vue
实例上的一个属性。- js的数据类型(基本类型和引用类型)
- 函数作用域
- 第一点无可厚非,data属性附着于 Vue 实例上
- 对于第二点js的数据类型,基本上大家都知道有基本类型和引用类型。
数据类型
基本数据类型: Number, String, Boolean, Null, Undefined, Symbol。简单的数据段,存放在栈
内存中,占据固定大小的空间
引用数据类型: Object(除了基本类型皆为对), 保存在堆
内存中, 引用类型的变量实际上保存的不是变量本身,而是指向该对象的指针。
栈(Stack) 和 堆(Heap)
栈
学过数据结构的都知道栈被称为后入先出
(LIFO,last-in-first-out)的数据结构。栈内存是内存中用于存放临时变量的一片内存块。当声明一个基本变量时,它就会被存储到栈内存中。
例如下面这段代码,他们在栈内存中存储的形式如下所示:
const a = 10;
const b = 20;
const c = a;
下图演示了这种基本数据类型赋值的过程:
很显然,a, c两个变量占用了不同的存储空间,所以他们之间也并没有什么联系。
栈内存的地址分配是连续的,所以在后续也不能对其进行进一步的扩充或者删除。
堆
堆内存的存储不同与栈,引用类型在栈内存中保存的实际上是对象在堆内存中的引用地址,过这个引用地址可以快速查找到保存中堆内存中的对象,变量其实是保存在栈内存中的一个指针,这个指针指向堆内存。
var obj1 = {
a: 1
};
var obj2 = {};
var obj3 = obj1;
obj3.b = 22;
console.log(obj1); // {a:1, b: 22}
从上面我们可以得知,当我改变obj3中的数据时,obj1
中数据也发生了变化;这就印证了我们前面说的,因为变量都是对象类型,属于引用类型,所以给obj3
赋值的只是栈中的地址,而不是真正保存在堆里的对象,当修改 obj3
的时候,会根据地址返回到堆内存中进行修改,因为他们的引用地址指向同一对象,因此我们只修改了obj3,obj1也同步改变。
下图展示引用类型如何保存在内存中:
我们在访问引用类型时,需要在栈内存中查找 对应的地址,在去堆内存中取得真正的值,访问速度自然不及栈内存。
可以看出,我们对引用类型复制时,只是将地址复制了一遍,修改的时候回相互影响,所以对引用类型进行复制的时候,应该将堆内存中的值复制,然后将新地址赋值给变量。这就涉及到了
深拷贝
.
- 第三点我们都知道js每个函数都有自己的
作用域
。
解释完上面三点,我们就来解释问题1:为什么 data
要写成函数而不是对象?
data 为对象的示例代码:
function MyCompnent() {};
MyCompnent.prototype.data = { age: 12 };
var Jack = new MyCompnent();
var Tony = new MyCompnent();
console.log(Jack.data.age === Tony.data.age); // true
Jack.data.age = 13;
console.log('Jack ' + Jack.data.age + '岁;' + 'Tony ' + Tony.data.age + '岁'); // Jack 13岁;Tony 13岁
data 为函数的示例代码:
function MyCompnent() {
this.data = this.data();
};
MyCompnent.prototype.data = function () {
return {
age: 12
}
};
var Jack = new MyCompnent();
var Tony = new MyCompnent();
console.log(Jack.data.age === Tony.data.age); // true
Jack.data = {age: 13};
console.log('Jack ' + Jack.data.age + '岁;' + 'Tony ' + Tony.data.age + '岁'); // Jack 13岁; Tony 12岁
我们利用上面两段代码模拟了Vue实例上的data,我们创建一个构造函数 MyCompnent
, 它相对于Vue,在其原型链上声明一个 data
属性,其实就相对 Vue.$data
, 然后声明两个实例,我们发现当data为对象的时候,两个实例相互影响,为函数的时候,那么就互不会影响。
tips:
这是一个经常在面试中会被问到的问题,vue的data为什么是函数而不是对象,以及js数据类型相关的问题,通过这篇帖子希望能彻底弄懂。
小结
Vue 里面data属性之所以不能写成对象的格式,是因为对象是对地址的引用。如果一个.vue 文件有多个子组件共同接收一个变量的话,改变其中一个子组件内此变量的值,会影响其他组件的这个变量的值。如果写成函数的话,因为函数作用域的存在,相互隔阂,不受影响。
问题2: 待补充…