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

我们知道 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 框架 —— 绑定外部传入方法_第1张图片
扫码关注前端周记公众号

你可能感兴趣的:(亲手实现一个简单的类 Vue 框架 —— 绑定外部传入方法)