类似undersore的链式调用(上)

553 阅读2分钟

前言

这边就不看undersore的源码了,直接开始源码中的链式调用是怎么完成的

链式调用

先举个例子,暂时先调用去重和map方法

let arr=[1,1,2,2,3,3,4,4,'a','A']
arr.unique(func).map(mapf)

上述代码会在执行完成之后,去重并且返回经过处理的数组,这就是链式调用,而func和mapf则是扩展函数,例如是否区分大小写,按什么标准来处理数组等等

首先用_来表示关键字

调用方式

_.unique(arr, func) 
_(arr).unique(func)

上面两行代码说明: _是一个function 因为function 也属于对象,所以符合上述代码的执行方式

获取 _

如下方代码

(function (root) {
    var _ = function () {

    }
    root._ = _
})(this)

先把unique和map方法写上

(function (root) {
    var _ = function () {

    }
    _.map = function (arr, callback) {
        return arr.map((item) => {
            callback ? callback(itme) : item
        })
    }
    _.unique = function (arr, callback) {
        let result = []
        arr.forEach((item) => {
            let target = callback ? callback(item) : item
            if (result.indexOf(target) === -1) {
                result.push(target)
            }
        });
        return result
    }
    root._ = _
})(this)

_.unique(arr, func)

可以发现这种情况下 _.unique(arr, func) 这种方式是可以调用的,用下方代码测试

      let arr = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, "a", "A"];
      let func = function (key) {
        return typeof key === "string" ? key.toLocaleLowerCase() : key;
      };
      console.log(_.unique(arr, func)); //[1, 2, 3, 4, 5, "a"]

_(arr).unique(func)

但是_(arr).unique(func) 这种方法是无法调用的,_()这种类似jquery中的无new化实例,后面跟的方法属于原型中的方法,
_()时,如果this指向的是window ,此时手动new 一个实例出来,此时想要调用方法,则需要在原型上面定义方法,但是如果像下面代码这样写,这样的话,同一个方法就需要写两遍,这种做法明显是不可取的,

首先,先无new化实例

(function (root) {
    var _ = function (obj) {
        if (!(this instanceof _)) {
            return new _(obj)  //无 new 实例
        }
        this.warp = obj
    }
    _.prototype.map = function () { }
    root._ = _
})(this)

所以需要获取所有的方法,并且遍历到原型里面
return new _(obj)这里为什么要把obj(调用时传入的数组之类的参数,类似_(arr))作为参数传入进去呢,因为_()时,内部会调用两次,第一次为执行普通函数,第二次为实例,obj需要在实例化时获取,所以需要把obj传进去

然后获取到所有方法

_.functions = function (obj) {
        let arr = []
        for (const key in obj) {
            arr.push(key)
        }
        return arr
    }

对每个方法遍历

    _.each = function (arr, callback) {
        for (let i = 0; i < arr.length; i++) {
            callback(arr[i])
        }
    }

混入到原型中

    _.mixin = function (obj) {
        _.each(_.functions(obj), function (key) {
            let func = obj[key]
            _.prototype[key] = function () {
                let args = [this.warp]
                Array.prototype.push.apply(args, arguments)
                return func.apply(this, args)
            }
            
        })
    }
    _.mixin(_)

这样每一个实例都可以调用原型上的方法

console.log(_(arr).unique(func));//[1, 2, 3, 4, 5, "a"]

下面贴上完整的代码

(function (root) {
    var _ = function (obj) {
        if (!(this instanceof _)) {
            return new _(obj)  //无 new 实例
        }
        this.warp = obj
    }
    
    _.map = function (arr, callback) {
        return arr.map((item) => {
            callback ? callback(itme) : item
        })
    }
    _.unique = function (arr, callback) {
        let result = []
        arr.forEach((item) => {
            let target = callback ? callback(item) : item
            if (result.indexOf(target) === -1) {
                result.push(target)
            }
        });
        return result
    }
    _.functions = function (obj) {
        let arr = []
        for (const key in obj) {
            arr.push(key)
        }
        return arr
    }
    _.each = function (arr, callback) {
        for (let i = 0; i < arr.length; i++) {
            callback(arr[i])
        }
    }
    _.mixin = function (obj) {
        _.each(_.functions(obj), function (key) {
            let func = obj[key]
            _.prototype[key] = function () {
                let args = [this.warp]
                Array.prototype.push.apply(args, arguments)
                return func.apply(this, args)
            }
            
        })
    }
    _.mixin(_)
    root._ = _
})(this)

这一篇只是为下一期的链式调用打下了基础,下面一期带来完整的链式调用,如果又错误或者更好的方法,希望大佬提出,谢谢