SOURCE

/**
 * @desc实现一个myCall
*/
Function.prototype.myCall = function(context) {
    if (Object.prototype.toString.call(this).slice(8, -1) !== 'Function') {
        throw new Error('调用类型必须是Function类型!');
    }
    // step1: 兼容一下 context为空或者为简单类型的情况
    context = context ? Object.create(context) : window;
    // step2: 获取参数
    const args = Array.prototype.slice.call(arguments, 1);
    // step3: 将this作为context的某个属性并调用
    context.fn = this;
    const result = context.fn(...args);
    // step4: 删除冗余的字段
    delete context.fn;
    return result;
}


/**
 * @desc实现一个myApply
*/

Function.prototype.myApply = function (context) {
    if (Object.prototype.toString.call(this).slice(8, -1) !== 'Function') {
        throw new Error('调用apply的必须是函数类型')
    }
    // step1: context 缺省的情况下使用window、为了避免简单类型,用Object.create 强转一下
    context = context ? Object.create(context) : window;
    // step2: 获取参数
    const args = arguments[1];
    // step3: 将this作为context的某个属性,并调用该属性执行
    context.fn = this;
    const result = context.fn(...args);
    // step4: 返回结果前删除冗余的字段
    delete context.fn;
    return result;
}

/**
 * @desc 实现一个myBind
*/
Function.prototype.myBind = function (context) {
    if (Object.prototype.toString.call(this).slice(8, -1) !== 'Function') {
        throw new Error('调用的对象类型必须是 Function 类型');
    }
    // this指向调用bind的那个函数
    const self = this;
    // 兼容context不存在,或者为简单类型
    context ? Object.create(context) : window;
    // 拿到除去this之外的参数;
    const args = Array.prototype.slice.call(arguments, 1);
    const returnFn = function () {
        const argsAdd = Array.prototype.slice.call(arguments);
        return self.apply(this instanceof returnFn ? this : context, [...args, ...argsAdd])
    };
    // 处理一下使用new Bind的情况
    const fn = function () { };
    fn.prototype = this.prototype;
    returnFn.prototype = new fn();
    return returnFn;
}

/**
 * @desc 实现一个new操作符
 * 1. 需要把原型链链到构造函数上
 * 2. 需要把构造函数执行一遍,并且执行结果返回
 * 3. 返回结果要注意一下,如果构造函数的执行结果是一个对象,那么就返回执行结果,否则返回新生成的对象
*/
function _new(fn) {
    // step1: 创建一个空对象、并且把对象的原型指向构造函数
    const obj = Object.create(fn.prototype);
    // step2: 借助apply,用生成的对象为this调用构造函数
    const res = fn.apply(obj, Array.prototype.slice.call(arguments, 1));
    // step3: 判断构造函数的返回值是否是对象类型,如果是,直接返回。如果不是,则返回新生成的对象
    return res instanceof Object ? res : obj;
}

/**
 * @desc 实现一个curry柯里化函数
*/
const sub_curry = (fn, ...args) => (...newArgs) => fn(...args, ...newArgs)

const curry = (fn, length = fn.length) => (...args) => {
    // 参数还不够多,调用 sub_curry把之前的参数暂存一下,并且返回一个函数
    if (args.length < length) {
        return curry(sub_curry(fn, ...args), length - args.length)
    } else {
        return fn(...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"]
console 命令行工具 X clear

                    
>
console