为了账号安全,请及时绑定邮箱和手机立即绑定

Vue原理解析:Vue 实例如何实现代理 data 对象属性的访问

标签:
Vue.js

对于初学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—————

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消