对于初学Vue.js的小伙伴而言,可能会认为Vue实例是一个很神奇的东西!因为它除了帮助我们完成双向绑定之外,还在某些细节方面为我们增加了一些理解上面的小烦恼!希望通过这篇文章能够为勤勉的你解惑~
看一段简单代码先:
new Vue({
el:"#myApp",
data:{
userName:"laoWangTou",
age:16
},
methods:{
run(){
// 输出结果:laoWangTou今年16岁了
console.log(this.userName+"今年"+this.age+"岁了");
}
},
created(){
// this为什么可以调用methods的run方法?
this.run();
}
})
对于以上代码可能会有两个小疑问:
1、为什么钩子函数中的 this.run 可以调用到methods对像下的方法run?
2、为什么methods对象下的run方法可以通过this获得data下的属性?
要弄明白这两个问题首先你要明白下面几个点:
- this即是通过Vue生成的实例vm
const vm = new Vue({
el:"#myApp",
created(){
console.log(vm === this);// true
}
})
- $data与data是相等的
const data ={};
const vm = new Vue({
el:"#myApp",
data,
created(){
console.log(this.$data === data);// true
}
})
console.log(vm.$data === data);// true
- $data的属性被修改,vm实例下的属性也会发生相应的变化
const vm = new Vue({
el:"#myApp",
data:{
userName:"laoWangTou",
age:16
},
created(){
this.$data.userName = "xiaoZhang"
this.$data.age = 18;
// 输出结果:xiaoZhang今年18岁了
console.log(this.userName+"今年"+this.age+"岁了");
}
})
// 输出结果:xiaoZhang今年18岁了
console.log(vm.userName+"今年"+vm.age+"岁了");
通过之前的两个疑问及得到的个结论,咱们可以先来个小猜测:
1、通过Vue生成的实例中有一属性为$data,其值为接收对象的data值
2、vm实例中代理了data的属性
3、methods下的方法赋值给了vm实例
于是,结合Vue.js的源码模拟出了以下较易理解的代码:
// 定义了一个构造函数
function Vue(options) {
this.$data = options.data || {};
this.initState(options);
}
Vue.prototype.initState = function (opts) {
if(opts.data)
this.initData(opts.data);
if(opts.methods)
this.initMethods(opts.methods);
if(opts.created)
opts.created.call(this);
}
Vue.prototype.initData = function (data) {
var keys = Object.keys(data);
var i = keys.length;
while (i--){
const key = keys[i];
this.proxy("$data",key);
}
}
Vue.prototype.initMethods = function (methods) {
for (var key in methods) {
this[key] = methods[key];
}
}
Vue.prototype.proxy =function(sourceKey, key) {
Object.defineProperty(this, key, {
get() {
return this[sourceKey][key]
},
set(val){
this[sourceKey][key] = val;
}
});
};
验证:
const vm = new Vue({
el:"#myApp",
data:{
userName:"laoWangTou",
age:16
},
methods:{
run(){
// 输出结果:laoWangTou今年16岁了
console.log(this.userName+"今年"+this.age+"岁了");
}
},
created(){
// this为什么可以调用methods的run方法?
this.run();
}
});
// 输出结果:laoWangTou今年16岁了
console.log(vm.userName+"今年"+vm.age+"岁了");
—————END—————