美文网首页Web前端之路让前端飞
亲手实现一个简单的类 Vue 框架 —— 绑定外部传入方法

亲手实现一个简单的类 Vue 框架 —— 绑定外部传入方法

作者: ac68882199a1 | 来源:发表于2017-04-30 17:00 被阅读190次

    我们知道 Vue 中传入的对象有一个属性对象methods,其中的属性方法会被绑定到 Vue 实例上,可以通过this访问到,那么我们这一篇文章就来实现一下方法的绑定

    【注:本节所有代码都是在上一节代码的基础上增加的,所以上一节的代码将会省略】

    首先确定我们预期的使用方式:

    var l = new Lue({
        methods: {
            init: function () {
                console.log(this)
            }
        },
        ready: function () {
              // 与上一节相同,先通过一个 $methods 作为所有方法被绑定到的对象
            this.$methods.init()
        }
    })
    

    根据上面的代码,我们大致可以推断出绑定方法的代码:

    function Lue () {
        this.$methods = {}
        if (typeof opts.methods === 'object') {
            for (var key in opts.methods) {
                if (typeof opts.methods[key] === 'function') {
                    this.$methods[key] = opts.methods[key]
                }
            }
        }
    
        if (typeof opts.ready === 'function') {
            opts.ready.call(this)
        }
    }
    

    执行后控制台输出一个包含init方法的对象,即我们传入的外部对象的methods属性,而不是我们期望的l实例。这是为什么呢?我们在 前端面试题——call与apply方法的异同这一节中已经剖析过了this的指向问题——this永远指向该方法被持有的对象,即谁(哪个对象)持有这个方法,this就指向这个对象。所以在这里打印出来的是methods对象,而不是我们所期望的l

    那我们该怎么做呢?很简单,用callapply方法改变this的指向

    但是这里又有一个问题:

    通过callapply改变this的函数会被立即执行

    所以在处理方法的绑定时,我们需要延迟绑定,即在该方法需要被执行时,再绑定到l上,但是又要能够通过this.$methods访问到这个方法

    是不是有点绕?没关系,直接上代码!

    function Lue () {
        this.$methods = {}
        if (typeof opts.methods === 'object') {
            this._bindMethods(opts.methods)
        }
        // 兼容当 methods 属性为方法,并且返回一个对象时的情况
        if (typeof opts.methods === 'function' && typeof opts.methods() === 'object') {
            this._bindMethods(opts.methods())
        }
      
       if (typeof opts.ready === 'function') {
           opts.ready.call(this)
       }
    }
    
    // 在 Lue 原型链上添加方法 _bindMethods
    Lue.prototype._bindMethods = function (obj) {
        var self = this
        for (var key in obj) {
            var val = obj[key]
            if (typeof val === 'function') {
                  // 放该属性为方法时,在 $methods 上创建一个同名方法
                // 这个方法的作用是改变传入的参数 $methods 属性上的对应方法的执行环境并执行
                // 两个连续的三目运算的作用是:当该方法无参数时,直接通过 call 改变执行环境并执行;当存在 1 个参数时,通过 call 方法并传入这个参数 arg;当参数多于 1 个时,通过 apply 方法并传入整个参数列表
                this.$methods[key] = function (arg) {
                var length = arguments.length
                length ? length > 1 ? val.apply(self, arguments) : val.call(self, arg)
                         : val.call(self)
                 }
            }
        }
    }
    

    以上代码修改后再次执行,控制台成功输出了我们预期的l对象

    大功告成!

    这一节的内容到这里就结束啦!传说中的短小精悍,直戳要点!嗯,明天就是劳动节啦,虽然今天已经是假期第二天了:)虽然有点短,但小伙伴们不要介意啊,下周一定补回来!大家节日快乐,玩好吃好!但也不要忘了学习哦!

    下面是重头戏!!!第一次公众号关注福利出炉~~~扫描二维码关注后回复【福利】即可领取

    【HTML5程序设计】电子版

    扫码关注前端周记公众号

    相关文章

      网友评论

        本文标题:亲手实现一个简单的类 Vue 框架 —— 绑定外部传入方法

        本文链接:https://www.haomeiwen.com/subject/xvsxtxtx.html