函数式编程-underscore整体结构

625 阅读3分钟

简介

什么是函数式编程?

百科定义:函数式编程是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。

函数式编程强调没有"副作用",意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的,在javascript中,对于数组的操作,有些是纯函数,有些是不纯的

var arr = [1, 2, 3, 4, 5]

//纯函数
arr.slice(0, 3) //不会改变arr的值,arr = [1, 2, 3, 4, 5]

//非纯函数
arr.splice(0, 3)    //会改变arr的值,arr = [4, 5]

underscore使用了函数式的特性,提供了一系列函数式方法,underscore会把自身绑定到唯一的全局变量 _ 上

_.each([1, 2, 3], alert);
=> alerts each number in turn...

_.map([1, 2, 3], function(num){ return num * 3; });
=> [3, 6, 9]
_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; });
=> [3, 6, 9]
_.map([[1, 2], [3, 4]], _.first);
=> [1, 3]

//去重
_.uniq([1, 2, 1, 4, 1, 3]);
=> [1, 2, 4, 3]

_.indexOf([1, 2, 3], 2);
=> 1

源码解读

初始化

underscore初始化,underscore在一个自执行函数里面执行代码,防止全局污染

(function(){
    //javascript self对象指窗口本身,它返回的对象跟window对象是一模一样的,也正因为如此,window对象的常用方法和函数都可以用self代替windo。下面相当于 root = window
    var root = typeof self == 'object' && self.self === self && self || typeof global == 'object' && global.global === global && global || this || {}

    var _ = function(obj) { //underscore构造函数
    }
  
    root._ = _  //将 _ 挂载到window对象上
})()

调用方式

underscore有两种调用方式,一种函数式风格,一种面向对象风格

// 函数式风格
_.each([1, 2, 3], function(item){
    console.log(item)
});

// 面向对象风格
_([1, 2, 3]).each(function(item){
    console.log(item)
});

第二种面向对象的风格,_([1, 2, 3])返回的是underscore实例,相当于 new _(),该实例再调用each方法,如何实现这一功能呢?underscore跟jquery实现还是有区别的,jquery使用的是共享原型的方式,下面是underscore方式

var _ = function(obj) {
    if (!(this instanceof _)) return new _(obj);
    this._wrapped = obj;
}
  1. 首次执行_()方法,this指的是window对象,所以会执行return new _(obj)
  2. 执行new _(obj)时候,this这时候指的是 _,会将 this. _warpped指向obj,即传进来的数据 [1, 2, 3]

mixin方法

上面说了undersore有两种调用方式,underscore源码内部都是 _ .map()=function、_ .each=function(){}这样的方式调用,mixin方法就是为了合并两种调用方式,同时将这些方法挂载到underscore原型上

var ArrayProto = Array.prototype;
var push = ArrayProto.push;

//判断obj是否是函数
_.isFunction = function(obj) {
    return typeof obj == 'function' || false;
};

//返回一个保存obj中的方法名称的数组
_.functions = function(obj) {
    var names = [];
    for (var key in obj) {
        if (_.isFunction(obj[key])) names.push(key);
    }
    return names.sort();
};

_.mixin = function(obj) {
    _.each(_.functions(obj), function(name) {   //name是underscore所拥有的所有方法名称(each,map...)
        var func = _[name] = obj[name];        
        _.prototype[name] = function() {        //给underscore原型上扩展each、map等方法
            var args = [this._wrapped];         //this._wrapped是储存传入的数据,即第二种风格传入的数据
            push.apply(args, arguments);        //将数据跟传入的参数合并 [this.wrapped, ...arguments]
            return func.apply(_, args);         //执行underscore内部方法,即执行第一种风格方法
        };
    });
    return _;
};

_.mixin(_);