编辑代码

const log = console.info
let fn, fn1, fn2, val, val1, val2
function foo(...args) {
    this.a && log('this.a:' + this.a)
    return args.reduce((tol, cur) => tol + cur)
}

Function.prototype._apply = function (obj, args) {
    obj = obj ? Object(obj) : global;
    const fn = Symbol()//保证obj属性不被重写
    obj[fn] = this
    const result = obj[fn](...args)
    delete obj[fn]
    return result
}
log(foo._apply({ a: 1 }, [2, 3]))

Function.prototype._call = function (obj, ...args) {
    return this._apply(obj, args)
}
log(foo._call({ a: 1 }, 2, 3))
log(foo._call(null, 2))

Function.prototype._bind = function (obj, ...args) {
    let self = this
    return function (...rest) {
        return self._call(obj, ...args, ...rest)
    }
}
fn = foo._bind({ a: 1 }, 2, 3);
log(fn(4))

const _ = {}
Function.prototype._partial = function (...args) {
    let self = this
    return function (...rest) {
        let i = 0
        args = args.map(item => item === _ ? rest[i++] : item)
        return self._call(this, ...args, ...rest.slice(i))
    }
}
fn2 = (x, y) => x + y
log(foo._partial(_, 2)())
log(fn2(3, 1, 1))

Function.prototype._thunk = function (...args) {
    let self = this
    return function (...rest) {
        return self._call(this, ...args, ...rest)
    }
}
Function.prototype._thunktopromise = function () {
    let self = this
    return new Promise(function (resolve, reject) {
        self(function (data) {
            if (data.err) return reject(data.err);
            resolve(data.res ? data.res : data)
        });
    });
}

fn = x => cb => cb(x)
fn1 = (x, cb) => cb(x)
var gen = function* () {
    log('gen-in')
    var r1 = yield fn(100);
    log('r1:', r1)
    var r2 = yield fn1._thunk(r1);//转换
    return r1 + r2
};
function thunkCo(fn) {
    var gen = fn();
    function next(data) {
        log('run-in')
        var result = gen.next(data);
        log(data, result)
        if (result.done) return result.value
        return result.value(next);
    }
    return next();
}
// log('thunkCo(gen):', thunkCo(gen))

fn = x => Promise.resolve(x)
gen = function* () {
    log('gen-in')
    var r2 = yield fn1._thunk(100)._thunktopromise();//转换
    log('r2:', r2)
    var r1 = yield fn(100);
    log('r1:', r1)
    return r1 + r2
};
function promiseCo(fn) {
    var gen = fn();
    function next(data) {
        log('run-in')
        var result = gen.next(data);
        log(data, result, result.done)
        if (result.done) return result.value
        return result.value.then(next);
    }
    return next();
}
// log('promiseCo:', promiseCo(gen).then(x => console.info('x:', x)))
// log('end')
//迭代器
Array.prototype._iterator = function () {
    let array = this;
    let i = 0;
    return {
        next: function () {
            return i < array.length ?
                { value: array[i++], done: false } :
                { value: undefined, done: true };
        }
    };
}
let it = [1, 2]._iterator()
// log(it.next())
// log(it.next())
// log(it.next())

Function.prototype._reduxThunk = (middleApi) => (next) => (action) => {
    if (typeof action == 'function') {
        console.log(1);
        return action(middleApi.dispatch, middleApi.getState);
    }

    console.log(2);
    return next(action);
}

var incAsy = () => (dispatch) => {
    console.log('等待2秒');
    setTimeout(() => {
        dispatch({ type: 'xxx' });
    },
        2000);
}
// store.dispatch(incAsy());
// https://blog.csdn.net/m0_37036014/article/details/102697130
// https://zhuanlan.zhihu.com/p/59596524
function iteratorCo(gen) {
    function toPromise(obj) {
        // log('obj:', obj);
        // if(!obj) return obj;
        // //promise
        // if(isPromise(obj)) return obj;
        // //object
        // if(isObject(obj)) return objectToPromise.call(this,obj)
        // //array
        // if(Array.isArray(obj)) return arrayToPromise.call(this,obj)
        // //function
        if ('function' == typeof obj) return thunkToPromise.call(this, obj);
        //generator
        if (isGeneratorFunction(obj) || isIterator(obj)) return Promise.resolve().then(() => iteratorCo.call(this, obj));
        function isIterator(obj) {
            return 'function' == typeof obj.next && 'function' == typeof obj.throw;
        }
        function isGeneratorFunction(obj) {
            let constructor = obj.constructor;
            if (!constructor) return false;
            if (constructor.name === 'GeneratorFunction' || constructor.displayName === 'GeneratorFunction') return true;
            return isIterator(obj);
        }
        function thunkToPromise(fn) {
            var ctx = this;
            return new Promise(function (resolve, reject) {
                fn.call(ctx, function (err, res) {
                    if (err) return reject(err);
                    if (arguments.length > 2) res = slice.call(arguments, 1);
                    resolve(res);
                });
            });
        }
        return obj
    }
    if (typeof gen === 'function') gen = gen();
    function next(data) {
        log('run-in', gen)
        var result = gen.next(data);
        log('run-in-result', data, result)
        if (result.done) return result.value
        let value = toPromise(result.value)
        log('value', value)

        return value.then(next);
    }
    return next();
}
function koa_compose(middleware) {
    return function* (next) {
        if (!next) next = () => { };
        var i = middleware.length;
        while (i--) {
            next = middleware[i].call(this, next);
            // log(1,next)
        }
        return yield* next;
    }
}
gen = koa_compose([
    function* (next) { log('1-start'); yield next; log('1-end') },
    function* (next) { log('2-start'); yield next; log('2-end') },
    function* (next) { log('3-start-end'); },
])
// iteratorCo(gen)

function koa2_compose(middleware) {
    return function (ctx) {
        function dispatch(i) {
            const fn = middleware[i]
            if (!fn) return Promise.resolve()
            try {
                return Promise.resolve(
                    fn(ctx, () => dispatch(i + 1))
                )
            } catch (err) {
                return Promise.reject(err)
            }
        }
        return dispatch(0)
    }
}
// koa2_compose([
//     async (ctx, next) => { log('1-start'); await next(); log('1-end') },
//     async (ctx, next) => { log('2-start'); await next(); log('2-end') },
// ])({})



Function.prototype._curry = function (...args) {
    let self = this
    let len = self.length;
    log(args.length, len, args)
    //简单版本
    // if (args.length >= len) return self.call(null, ...args);
    // return (...rest) => self._curry(...args, ...rest)
    //支持占位符_的版本
    if (!args.some(item => item === _) && args.length >= len) return self.call(null, ...args);
    return (...rest) => {
        let positon = 0
        args = args.map(item => {
            return item === _ ? rest[positon++] : item
        })
        return self._curry(...args, ...rest.slice(positon))
    }
}
fn2 = function (x, y, z, i) { return [].slice.call(arguments).reduce((tol, cur) => tol + cur) }
// log('_curry:', fn2._curry(1, _)(_)(2))
// log('_curry:', fn2._curry(_, _, _, 4)(_, _, 3)(_, 2)(1));
// log('_curry:', fn2._curry(1, _, _, 4)(2, 3));
// log('_curry:', fn2._curry(1, _, _, 4)(_, 3)(2));
// log(foo._curry(_, 2)()) 不支持不定参数foo的curry

// 帮忙理解
// compose(f, g, h) (...arg) => f(g(h(...args)))[f,g,h]
// (tol,cur)=>(...args)=>tol(cur(...args))
// s1 = (...args)=>f(g(...args))
// s2 = (...args)=>s1(h(...args))
Array.prototype._compose = function compose() {
    let funcs = this
    // funcs是一个保存着所有参数函数的数组
    // 如果没有传递任何参数,就返回一个函数,这个函数是输入什么得到什么。
    if (funcs.length === 0) {
        return arg => arg
    }
    // 只传递一个参数的时候,就直接把这个函数返回
    if (funcs.length === 1) {
        return funcs[0]
    }
    return funcs.reduce((tol, cur) => {
        return (...args) => tol(cur(...args));
    })
}
let dispatch = action=>{
   console.info(action);
   return action
 }
 fn1 = next => action =>{
  console.info('f-start');
  action += 1
  next(action);
  console.info('f-end');
}
 fn2 = next => action =>{
  console.info('f2-start');
  action += 1
  next(action);
  console.info('f2-end');
}
[fn1,fn2]._compose()(dispatch)(0)


// https://www.jianshu.com/p/54609c2eec4e flat实现
Object.defineProperty(Array.prototype, '_flat', {
    value: function () {
        return this.reduce((pre, cur) => {
            return pre.concat(Array.isArray(cur) ? cur._flat() : cur);
        }, []);
    }
})
// log([[1],,[[2,3]]]._flat())

//截流
function throttle(fn, wait) {
    var timer;
    return function (...args) {
        if (!timer) {
            timer = setTimeout(() => timer = null, wait);
            // console.log(timer)
            return fn.apply(this, args)
        }
    }
}
fn = function () { console.log("btn clicked") }
fn1 = throttle(fn, 100);
fn1();
fn1();
setTimeout(() => fn1(), 200)