/**
* @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