手写

防抖&节流

// 使用场景 表单提交 防止重复提交, 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.datahttps://www.it610.com/article/= '' try { exector(this.resolve, this.reject)} catch (err) { throw new Error(err) } }resolve = (value) => { if (this.status !== 'pending') { return }this.status = 'resolved' this.data = https://www.it610.com/article/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 = https://www.it610.com/article/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 = 0const 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 = https://www.it610.com/article/`${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; } }

    推荐阅读