SOURCE

/**
 * @desc call方法
*/
Function.prototype.myCall = function (context) {
    if (typeof this !== 'function') {
        console.error('只有函数上才有call方法');
        return;
    }
    // step1: 兼容context为空的情况
    context = context ? Object.create(context) : window;
    // step2: 获取参数
    const args = Array.prototype.slice.call(arguments, 1);
    // step3: 把this座位context的一个属性,并且调用
    const res = context.fn = this;
    context.fn(...args);
    // step4: 删除多余的fn属性
    delete context.fn;
    return res;
}

/**
 * @des apply方法
*/
Function.prototype.myApply = function (context) {
    if (typeof this !== 'function') {
        console.error('只有函数上有apply方法');
        return;
    }
    // step1: 对context做兜底
    context = context ? Object.create(context) : window;
    // step2: 获取参数
    // step3: 将this作为context的某个参数,执行
    context.fn = this;
    const res = context.fn(...arguments[1]);
    // step4: 删除多余的fn属性
    delete context.fn;
    return res;
}

/**
 * @desc bind方法
*/
Function.prototype.myBind = function (context, ...args) {
    if (typeof this !== 'function') {
        console.error('只有函数上有apply方法');
        return;
    }
    // step1: 对context做兜底
    context = context ? Object.create(context) : window;
    // step2: 获取参数
    // step3: 返回一个函数 (这个函数,可能在下次调用的时候传参)
    const self = this;
    const returnFunc = function() {
        // 使用 apply来调用
        // 最后调用的时候判断一下
        self.apply(this instanceof returnFunc ? this : context, [...args, ...arguments])
    }
    return returnFunc;
}

/**
 * @desc 实现一个new操作符
*/
function _new (fn, ...args) {
    // step1: 使用指定原型创建一个新的对象
    const obj = Object.create(fn.prototype);
    // step2: 要把新对象做为this 放到fn函数要执行一下,并且把参数带进去
    const res = fn.apply(obj, [...args]);
    // step3: 如果返回对象是object类型,直接返回,否则返回obj
    return res instanceof Object ? res : obj;
}

/**
 * @desc 实现一个柯里化函数
*/

function curry(fn, ...args) {
    // 获得函数的参数个数
    const length = fn.length;
    // 参数够的话直接执行
    if (args.length >= length) {
        // 为了不修改this指向,用apply调用
        return fn.apply(this, [...args]);
    } else {
        // 参数不够的话,就先将当此调用的函数存下来,等参数够了再用
        return function(...nextArgs) {
            return curry.apply(this, [fn, ...args, ...nextArgs])
        }
    }    
}

/**
 * @desc 实现一个compose
*/
const compose = function(...funcs) {
    if (funcs.length === 0) {
        return (arg) => arg;
    } else if (funcs.length === 1) {
        return funcs[0];
    }
    return funcs.reduce((a, b) => (...args) => a(b(...args)))
}


// ===============================  测试代码 ============================
function sayHello(param1, param2, param3) {
    console.log(this.name, param1, param2);
}

const thisObj = {
    name: 'zaoren'
}

console.log('call test:------------------------------------------');
sayHello.call(thisObj, 'day', 'day up');
// sayHello.myCall(thisObj, 'day', 'day up');

console.log('apply test:------------------------------------------');
sayHello.myApply(thisObj, ['day', 'day up']);


console.log('bind test:------------------------------------------');
const testBind1 = sayHello.myBind(thisObj, 'day')('day up');

console.log('bind 构建函数 new test:--------------------------------');
const bindCurry = sayHello.myBind(thisObj, 'day');
// 使用构造函数的形式来调用bind后的函数时, undefined day day up是对的。因为改变了this指向
const testBind2 = new bindCurry('day up');


function Student(name) {
    this.name = `${name}, day day up`;
}
console.log('new test:------------------------------------------');
const student = _new(Student, 'zaoren');
console.log('student', student.name);

console.log('curry test:------------------------------------------');
var fn = curry(function(a, b, c) {
  return `${a} ${b} ${c}`;
});

console.log( fn("zaoren", "day", "dayup")); // ["a", "b", "c"]
console.log( fn("zaoren", "day")("dayup")); // ["a", "b", "c"]
console.log( fn("zaoren")("day")("dayup")); // ["a", "b", "c"]
console.log( fn("zaoren")("day", "dayup")); // ["a", "b", "c"]

// compose(f, g, h) 就会得到 (...args) => f(g(h(...args)))
console.log('compose test:------------------------------------------');
const dispatch1 = function(str) {
    // dosomething;
    return str + ' day'
}
const dispatch2 = function(str) {
    return str + ' dayup'
}
const dispatch3 = function(str) {
    return str + '!'
}

const composedFunc = compose(dispatch3,dispatch2, dispatch1);
console.log('compose res', composedFunc('zaoren'));
console 命令行工具 X clear

                    
>
console