手写

防抖&节流

// 使用场景 表单提交 防止重复提交, input搜索
function debounce(fn, delay) {
    let timer = null
    return function(...args) {
        if (timer) clearTimeout(timer)
        setTimeout(() => {
            fn.apply(this, args)
        }, delay)
    }
}
// 滚动,resize,节流
function throttle(fn, delay) {
    let flag = false
    return function(...args) {
        if (flag) return
        flag = true
        setTimeout(() => {
            fn.apply(this, args)
            flag = false
        }, delay)
    }
}

发布订阅

// 发布&订阅者
class EventEmitter {
    constructor() {
        this.events = {}   
    }

    once = function(type, cb) {
        const self = this
        function temp(...args) {
            cb.apply(null, args)
            self.off(type, temp)
        }
        self.on(type, temp)
    }

    emit = function(type, ...args) {
        const events = this.events[type]
        events && events.forEach(cb => {
           cb.call(null, ...args)
        })
    }

    on = function(type, cb) {
        if (this.events[type]) {
            this.events[type].push(cb)
        } else {
            this.events[type] = [cb]
        }
    }

    off = function(type, cb) {
        if (this.events[type]) {
            const index = this.events[type].indexOf(cb)
            this.events[type].splice(index, 1)
        }
    }
}

Scheduler,控制并发次数

class Scheduler {
    constructor() {
        this.count = 2
        this.queue = []
        this.run = []
    }

    add = (task) => {
       this.queue.push(task)
       return this.scheduler()       
    }

    scheduler = () => {
        if (this.run.length < this.count && this.queue.length) {
            const p = this.queue.shift()
            const promise = p().then(res => {
                this.run.splice(this.run.indexOf(promise), 1)
            })
            this.run.push(promise)
            return promise
        } else {
            return Promise.race(this.run).then(this.scheduler)
        }
    }
}


const timeout = (time) => new Promise(resolve => {
    setTimeout(resolve, time)
})

const scheduler = new Scheduler()
const addTask = (time, order) => {
    scheduler.add(() => timeout(time)).then(() => console.log(order))
}

addTask(10000, '1')
addTask(5000, '2')
addTask(3000, '3')
addTask(4000, '4')
// 2,3,1,4

Promise

class MyPromise {
    constructor(exector) {
        this.status = 'pending' // pending | resolved | rejected
        this.callbacks = []
        this.data = ''
        try {
            exector(this.resolve, this.reject)

        } catch (err) {
            throw new Error(err)
        }
    }

    resolve = (value) => {
        if (this.status !== 'pending') {
            return
        }

        this.status = 'resolved'
        this.data = value
        if (this.callbacks.length) {

            setTimeout(() => {
                this.callbacks.forEach(({ onFulfill }) => {
                    onFulfill(this.data)
                })
            })


        }
    }

    reject = (value) => {
        if (this.status !== 'pending') {
            return
        }

        this.status = 'rejected'
        this.data = value
        if (this.callbacks.length) {

            setTimeout(() => {
                this.callbacks.forEach(({ onReject }) => {
                    onReject(this.data)
                })
            })

        }
    }

    then = (resolvecb, rejectcb) => {

        const onFulfill = typeof resolvecb === 'function' ? resolvecb : (value) => value
        const onReject = typeof rejectcb === 'function' ? rejectcb : (reason) => { throw new Error(reason) }


        return new MyPromise((resolve, reject) => {

            const handle = (cb) => {
                try {
                    const res = cb(this.data)
                    if (res instanceof MyPromise) {
                        res.then(resolve, reject)
                    } else {
                        resolve(res)
                    }
                } catch (e) {
                    reject(e)
                }
            }

            if (this.status === 'pending') {
                this.callbacks.push({
                    onFulfill: () => handle(onFulfill),
                    onReject: () => handle(onReject)
                })
            } else if (this.status === 'resolved') {
                setTimeout(() => {
                    handle(onFulfill)
                })
            } else {
                setTimeout(() => {
                    handle(onReject)
                })
            }

        })

    }


    catch = (cb) => {
        return new MyPromise((resolve, reject) => {
            this.then(undefined, reason => cb(reason))
        })

    }

}


MyPromise.resolve = function (val) {
    return new MyPromise((resolve, reject) => {
        if (val instanceof MyPromise) {
            val.then(resolve, reject)
        } else {
            resolve(val)
        }
    })
}

MyPromise.reject = function (reason) {
    return new MyPromise((resolve, reject) => {
        if (reason instanceof MyPromise) {
            reason.then(resolve, reject)
        } else {
            reject(reason)
        }
    })
}

MyPromise.allSettled = function (arr) {
    const res = []
    return new MyPromise((resolve, reject) => {
        arr.forEach((p, index) => {
            p.then(val => {
                res.push({
                    type: 'resolve',
                    data: val
                })
                if (res.length === arr.length) {
                    resolve(res)
                }
            }, reason => {
                res.push({
                    type: 'reject',
                    data: reason
                })
                if (res.length === arr.length) {
                    resolve(res)
                }
            })
        })
    })
}

promise 限制并发次数

function asyncPools(limit, arr, iteratorFn) {
    let ret = []
    let executing = [] // 进行中
    let i = 0

    const enqueue = function () {
        if (i === arr.length) {
            return Promise.resolve()
        }
        const item = arr[i++]
        const p = iteratorFn(item)
        ret.push(p)
        executing.push(p)
        p.then(() => executing.splice(executing.indexOf(p), 1))

        if (executing.length >= limit) {
            return Promise.race(executing).then(enqueue)
        } else {
            return Promise.resolve().then(() => enqueue())
        }
    }

    return enqueue().then(() => {
        console.log('ret', ret)
        return Promise.all(ret)
    })
}

const timeout = i => new Promise(resolve => {
    console.log(i);
    setTimeout(() => {
        console.log('cb', i)
        return resolve(i)
    }, i)
});

asyncPools(3, [1000, 5000, 3500, 2000], timeout).then((res) => {
    console.log('res', res)
})

Generator模拟实现async await

function* generatorFun() {
    let a = yield Promise.resolve('A')
    let b = yield Promise.resolve('B')
    return a + b
  }
  
  function run(gen) {
    return new Promise(function (resolve) {
      // 执行Generator函数
      let g = gen()
      const next = (context) => {
        let { done, value } = g.next(context)
        if (done) {
          // 完成返回
          resolve(value)
        } else {
          // 未完成继续执行next函数,并传入本次执行结果
          value.then(next)
        }
      }
      next()
    })
  }

// run 为执行函数
run(generatorFun).then(res => console.log(res)) // AB

call/apply/bind/new/create

// call
Function.prototype.myCall = function(context, ...args) {
    context.fn = this
    if (typeof context.fn !== 'function') {
        throw new Error('not function')
    }
    const res = context.fn(...args)  
    delete context.fn
    return res
}
// apply
Function.prototype.myApply = function(context, args) {
    context.fn = this
    if (typeof context.fn !== 'function') {
        throw new Error('not function')
    }
    const res = context.fn(...args)  
    delete context.fn
    return res
}
// Object.create
function create(prototype, properties = {}) {
    function F() {}
    F.prototype = prototype
    const obj = new F()
    Object.defineProperties(obj, properties)
    return obj
}
// bind
function.prototype.myBind =  function (parentContext, ...args1) {
    if (typeof this !== 'function') {
        throw new Error('not function')
    }
    const fn = this
    const fBound = function (...args2) {
        const context = this instanceof fBound ? this : parentContext
        return fn.myApply(context, args1.concat(args2))
    }
    // 访问原函数的原型上的方法,通过Object.create拷贝
    fBound.prototype = create(fn.prototype)
    return fBound
}
// new
function myNew(fn, ...args) {
    var obj = create(fn.prototype)
    const res = fn.myApply(obj, args)
    return typeof res === 'object' ? res : obj
}

组合继承

function SuperType(name) {
    this.name = name
    this.colors = ['red']
}
SuperType.prototype.getName = function() {
    console.log('getName', this.name)
}

function SubType(name, age) {
    SuperType.call(this, name)
    this.age = age
}
// 减少父类少调用一次
function inheritPrototype(subType, superType) {
    let prototype = Object.create(superType.prototype)
    prototype.constructor = subType
    subType.prototype = prototype
}

inheritPrototype(SubType, SuperType)
// 扩展原型方法
SubType.prototype.getAge = function() {
    console.log('getAge', this.age)
}

JSONP的实现

// 客户端
function jsonp({url, params, callback}) {
    return new Promise((resolve, reject) => {
        //创建script标签
        let script = document.createElement('script');
        //将回调函数挂在 window 上
        window[callback] = function(data) {
            resolve(data);
            //代码执行后,删除插入的script标签
            document.body.removeChild(script);
        }
        //回调函数加在请求地址上
        params = {...params, callback} //wb=b&callback=show
        let arrs = [];
        for(let key in params) {
            arrs.push(`${key}=${params[key]}`);
        }
        script.src = `${url}?${arrs.join('&')}`;
        document.body.appendChild(script);
    });
}

// 使用
function show(data) {
    console.log(data);
}
jsonp({
    url: 'http://localhost:3000/show',
    params: {
        //code
    },
    callback: 'show'
}).then(data => {
    console.log(data);
});

// 服务端
//express启动一个后台服务
let express = require('express');
let app = express();

app.get('/show', (req, res) => {
    let {callback} = req.query; //获取传来的callback函数名,callback是key
    res.send(`${callback}('Hello!')`);
});
app.listen(3000);

柯里化&组合

// 柯里化
function curry(fn) {
    return function next(...args) {
        if (args.length < fn.length) {
            return function(..._args) {
                return next(...args.concat(..._args))
            }
        } 
        return fn(...args)
    }
}
function add(a, b, c) {
    return a + b + c
}

const newAdd = curry(add)
console.log(newAdd(1)(2)(3))
console.log(newAdd(1,2)(3))
console.log(newAdd(1)(2,3))
console.log(newAdd(1,2,3))

// 组合
function compose(...fns) {
    return function(...args) {
        return fns.reverse().reduce((acc, cur) => {
            return typeof acc === 'function' ? cur(acc(...args)) : cur(acc)
        })
    }
}

function fn1(x){
    return x + 1
}

function fn2(x){
    return x * 10
}

function fn3(x){
    return x - 1
}
var fn = compose(fn1, fn2, fn3)
console.log(fn(2))

redux

function createStore(reducer, prePayload) {

  let currentState = prePayload;
  let listeners = [];

  function getState() {
    return currentState;
  }

  function dispatch(action) {
    currentState = reducer(currentState, action);

    for(let i = 0; i < listeners.length; i++) {
      listeners[i]();
    }
  }

  function subscribe(func) {
    let isSubscribed = false;

    if (typeof func === 'function') {
      if (!listeners.includes(func)) {
        listeners.push(func);
        isSubscribed = true;
      }
    }

    return function unSubscribe() {
      if (!isSubscribed) {
        return;
      }

      let index = listeners.indexOf(func);
      listeners.splice(index, 1);
    }
  }

  dispatch({type: 'INIT'});

  return {
    getState,
    dispatch,
    subscribe,
  }
}

export default function combineReducers(reducers) {
  const reducerKeys = Object.keys(reducers);

  return function combine(state = {}, action) {

    let nextState = {};
    let isChanged = false;

    for(let i = 0; i < reducerKeys.length; i++) {
      let key = reducerKeys[i];
      let reducer = reducers[key];
      let stateForKey = state[key];

      nextState[key] = reducer(stateForKey, action);
      isChanged = isChanged || nextState !== state;
    }

    return isChanged ? nextState : state;
  }
}

你可能感兴趣的:(前端javascript)