code

类型

isType

function isType(type){
    return function (o){
        return Object.prototype.toString.call(o)===`[object ${type}]`
    }
}

防抖

function debounce(fn, delay) {
  let timer;
  return function (...args) {
    const context = this;
    clearTimeout(timer);
    timer = setTimeout(fn.bind(context, ...args), delay);
  };
}

节流

function throttle(fn, time) {
  let canCall = true;

  return function (...args) {
    if (!canCall) return;
    canCall = false;
    fn(...args);
    setTimeout(() => {
      canCall = true;
    }, time);
  };
}

实现 new

function newObject() {
  var obj = Object.create(null);
  //去除参数里的构造函数
  const Constructor = [].shift.call(arguments);
  obj.__proto__ = Constructor.prototype;
  Constructor.apply(obj, arguments);
  return obj;
}

function factory(name, age) {
  this.name = name;
  this.age = age;
}

var obj = newObject(factory, "xjq", 23);

实现 call

  Function.prototype.call2 = function (context) {
    // 首先要获取调用call的函数,用this可以获取
    context.fn = this;
    const obj = [].shift.call(arguments);
    obj.fn(...arguments);
    delete obj.fn;
  };

实现bind

Function.prototype.bind2 = function (o) {
  const context = this
  return function () {
    const symbol = Symbol()
    o[symbol] = context
    o[symbol](...arguments)
    delete o[symbol]
  }
}

实现 instanceof

function _instanceof(l, r) {
  const f = r.prototype
  while (true) {
    if (l === f) {
      return true
    }
    if (!l) {
      return false
    }
    l = l.__proto__
  }
}

实现 Promise

function Promise(fn) {
  this.state = 'pending'
  this.value = null
  this.callbacks = []
  fn(this._resolve.bind(this), this._reject.bind(this))
}

Promise.prototype._resolve = function (value) {
  if (this.state === 'pending') {
    this.state = 'fullfilled'
    this.value = value
    this.callbacks.forEach((fn) => this._handle(fn))
  }
}

Promise.prototype._reject = function (value) {
  if (this.state === 'pending') {
    this.state = 'rejected'
    this.value = value
    this.callbacks.forEach((fn) => this._handle(fn))
  }
}

Promise.prototype._handle = function (callback) {
  if (this.state === 'pending') {
    this.callbacks.push(callback)
    return
  }
  let cb = this.state === 'fullfilled' ? callback.onFullfilled : callback.onRejected
  if (!cb) {
    cb = this.state === 'fullfilled' ? callback.resolve : callback.reject
    cb(this.value)
    return
  }
  let ret
  try {
    ret = cb(this.value)
    cb = this.state === 'fullfilled' ? callback.resolve : callback.reject
  } catch (error) {
    ret = error
    cb = callback.reject
  } finally {
    cb(ret)
  }
}

Promise.prototype.then = function (onFullfilled, onRejected) {
  return new Promise((resolve, reject) => {
    this._handle({
      onFullfilled: onFullfilled || null,
      onRejected: onRejected || null,
      resolve,
      reject,
    })
  })
}

Promise.prototype.catch = function (onError) {
  return this.then(null, onError)
}


Promise.prototype.finally = function (onFinally) {
  if (typeof onFinally !== 'function') return this.then()
  let promise = this.constructor
  return this.then(
    (value) => promise.resolve(onFinally()).then(() => value),
    (reason) =>
      promise.resolve(onFinally()).then(() => {
        throw reason
      })
  )
}

Promise.resolve = function (value) {
  if (value && value instanceof Promise) {
    return value
  } else if (value && value instanceof Object && value.then instanceof Function) {
    const then = value.then
    return new Promise((resolve) => then(resolve))
  } else {
    return new Promise((resolve) => resolve(value))
  }
}

Promise.reject = function (value) {
  if (value && value instanceof Object && value.then instanceof Function) {
    const then = value.then
    return new Promise((resolve, reject) => then(reject))
  } else {
    return new Promise((resolve, reject) => reject(value))
  }
}

Promise.all = function (promiseList) {
  return new Promise((resolve, reject) => {
    const resList = []
    promiseList.forEach((p, index) => {
      p.then(
        (res) => {
          resList[index] = res
          if (resList.length === arr.length) {
            resolve(resList)
          }
        },
        (err) => reject(err)
      )
    })
  })
}

Promise.race = function (promiseList) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promiseList.length; i++) {
      Promise.resolve(promiseList[i]).then(
        (res) => {
          resolve(res)
        },
        (err) => {
          reject(err)
        }
      )
    }
  })
}

实现 reduce

function _reduce(fn, initialValue) {
  const arr = this
  let i = 0
  if (initialValue === undefined) {
    initialValue = arr[0]
    i++
  }
  for (; i < arr.length; i++) {
    initialValue = fn(initialValue, arr[i], i)
  }
  return initialValue
}

for of

function forOf(fn) {
  const it = this[Symbol.iterator]()
  while (true) {
    const { value, done } = it.next()
    if (done) break
    fn(value)
  }
}

const arr = [1, 2, 3, 4]

forOf.call(arr, (e) => {
  console.log(e)
})

jsonp

function jsonp({ url, callback }) {
  const script = document.createElement('script')
  script.src = url + '?cb=' + callback.name
  document.body.appendChild(script)
}

function fn(data) {
  console.log('data', data)
}

jsonp({
  url: 'http://127.0.0.1:3000',
  callback: fn,
})

// 后端返回的是javascript代码
// fn({a:1})

柯里化函数

const add = (args) => args.reduce((a, b) => a + b, 0)

function currying(func) {
  const args = []
  return function result(...rest) {
    if (rest.length) {
      args.push(...rest)
      return result
    } else {
      return func(args)
    }
  }
}

响应式原理

Proxy

const app = document.querySelector('#app')

var data = {
  t1: 't1',
  t2: 't2',
  t3: [1, 2],
  t4: { a: 1, arr: [1, 2] },
}

function proxy(target, handler) {
  Object.keys(target).forEach((key) => {
    if (target[key] instanceof Array || target[key] instanceof Object) {
      target[key] = proxy(target[key], handler)
    }
  })
  return new Proxy(target, {
    get: function (obj, key) {
      return obj[key]
    },
    set: function (obj, key, newValue) {
      obj[key] = newValue
      handler()
      return true
    },
  })
}

var dataProxy = proxy(data, update)

function update() {
  const { t1, t2, t3, t4 } = dataProxy
  document.getElementById('app').textContent = `t1:${t1},t2:${t2},t3:${t3.map((o) => o)},t4:${t4.arr.map((v) => v)}`
}

update()

Object.defineProperty

const app = document.querySelector('#app')

var data = {
  t1: 't1',
  t2: 't2',
  t4: { a: 1 },
}

function reactive(target, handler) {
  Object.keys(target).forEach((key) => {
    if (target[key] instanceof Object) {
      reactive(target[key], handler)
    } else {
      let tar = target[key]
      console.log(key, tar)
      Object.defineProperty(target, key, {
        get: function () {
          return tar
        },
        set: function (newValue) {
          if (tar !== newValue) {
            tar = newValue
            handler()
          }
        },
      })
    }
  })
}

reactive(data, update)

function update() {
  const { t1, t2, t4 } = data
  document.getElementById('app').textContent = `t1:${t1},t2:${t2},t4:${t4.a}`
}

update()

数组监听

function MyArray() {}

function clone(prototype) {
  function F() {}
  F.prototype = prototype
  return new F()
}

function inherit(p, o) {
  let prototype = clone(o.prototype)
  prototype.constructor = o
  p.prototype = prototype
}

inherit(MyArray, Array)

const _methodKey = ['push', 'pop', 'shift']
const _method = _methodKey.reduce((acc, cur) => {
  acc[cur] = MyArray.prototype[cur]
  return acc
}, {})

MyArray.prototype.push = function (params) {
  this.update('push')
  _method['push'].call(this, params)
}

MyArray.prototype.pop = function (params) {
  this.update('pop')
  _method['pop'].call(this, params)
}

MyArray.prototype.update = function (type) {
  console.log(type)
}

const arr = new MyArray()
arr.push(3)
arr.pop()
arr.push(3)

console.log(arr)

Event类实现

class Event {
  constructor() {
    this.event = {}
    this.maxListener = 5
    this.listenerCount = 0
  }
  on(type, fn) {
    if (this.listenerCount >= this.maxListener) {
      throw new Error('事件数量超限')
    }
    let hasEvent = !!this.event[type]
    if (typeof fn === 'function') {
      if (hasEvent) {
        this.event[type].push(fn)
      } else {
        this.event[type] = [fn]
      }
    }
    if (!hasEvent) this.listenerCount++
  }

  once(type, fn) {
    const _this = this
    function newFn() {
      fn(...arguments)
      _this.removeListener(type, newFn)
    }
    this.on(type, newFn)
  }

  emit(type, params) {
    if (this.event[type]) {
      this.event[type].forEach((fn) => fn(params))
    }
  }

  setMaxListeners(count) {
    this.maxListener = count
  }

  listeners(type) {
    return this.event[type] || []
  }

  removeAllListener(type) {
    this.event[type] = null
  }
  removeListener(type, listener) {
    if (this.event[type]) {
      this.event[type] = this.event[type].filter((fn) => listener !== fn)
    }
  }

  addListener(type, fn) {
    this.on(type, fn)
  }
}

const e = new Event()
function a1() {
  console.log('a1')
}

function a2() {
  console.log('a2')
}

e.once('a', a1)
e.on('a', a2)
e.emit('a')
e.emit('a')

并发限制的异步调度器

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

  addTask(task) {
    this.queue.push(task)
    return this.run()
  }

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

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

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

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

实现 redux

实现

export function createStore(reducer, enhancer) {
  let state = {}
  let isDispatching = false

  let listeners = []

  if (typeof enhancer === "function") {
    return enhancer(createStore)(reducer)
  }

  function getState() {
    return state
  }

  function dispatch(action) {
    if (typeof action.type === undefined) {
      throw new Error("action has not type")
    }
    if (isDispatching) {
      throw new Error("is dispatching")
    }

    try {
      isDispatching = true
      state = reducer(state, action)
      console.log(state)
      listeners.forEach((fn) => fn())
    } catch (error) {
      console.log(error)
      isDispatching = false
    }
  }

  function subscribe(listener) {
    listeners.push(listener)
    return listeners.filter((fn) => listener !== fn)
  }

  return {
    getState,
    dispatch,
    subscribe,
  }
}

export function dispatchBook(payload) {
  return { type: "BOOK", payload }
}

export function reducerBook(state = {}, action) {
  switch (action.type) {
    case "BOOK":
      return { ...state, name: action.payload }
  }
}

export function bindActionCreators(actionCreators, dispatch) {
  return Object.keys(actionCreators).reduce((acc, cur) => {
    acc[cur] = function (...args) {
      dispatch(actionCreators[cur](...args))
    }
    return acc
  }, {})
}

export function combineReducers(reducers) {
  return (state, action) => {
    return Object.keys(reducers).reduce((acc, cur) => {
      acc[cur] = reducers[cur](state[cur], action)
      return acc
    }, {})
  }
}

export function applyMiddleware(middleWares) {
  return (createStore) => (reducer) => {
    let store = createStore(reducer)
    let newDispatch = compose(middleWares.map((middleware) => middleware(store)))(store.dispatch)
    return { ...store, dispatch: newDispatch }
  }
}

export function compose(args) {
  return args.reduce(
    (acc, cur) =>
      (...args) =>
        acc(cur(...args))
  )
}

test

import { combineReducers, createStore, applyMiddleware, bindActionCreators } from "./index"

function reduxLogger(store) {
  return (dispatch) => (action) => {
    console.log(store.getState())
    dispatch(action)
    console.log(store.getState())
  }
}

function reduxCustom(store) {
  return (dispatch) => (action) => {
    dispatch(action)
    console.log("c", store.getState())
  }
}

const mergeReducers = combineReducers({ book: reducerBook })
const store = createStore(mergeReducers, applyMiddleware([reduxCustom, reduxLogger]))

const actions = bindActionCreators({ dispatchBook }, store.dispatch)

store.subscribe(() => {
  // console.log(11)
})

actions.dispatchBook("xxx")

实现 react-redux

const { Component } = require("react");
const { bindActionCreators } = require("redux");

class Provider extends Component{
  getChildContent(){
    return {store:this.props.store}
  } 
  render(){
    return this.props.children
  }
}


function connect(mapStateToProps,mapDispatchToProps){
  return function(WrapperComponent){
    class ProxyComponent extends Component{
      constructor(props,context){
        super(props,context)
        this.store=context.store
        this.state=mapStateToProps(this.store.getState())
      }

      render(){
        let actions
        if(typeof mapDispatchToProps==='function'){
          actions=mapDispatchToProps(this.store.dispatch)
        }else if(typeof mapDispatchToProps==='object'){
          actions=bindActionCreators(mapDispatchToProps,this.store.dispatch)
        }
        return <WrapperComponent {...this.state} {...actions}/>
      }
    }
    return ProxyComponent
  }
}

数组

乱序

扁平化

function flatten(arr) {
  let res = []
  arr.forEach((item) => {
    if (Array.isArray(item)) {
      res = [...res, flatten(item)]
    } else {
      res.push(item)
    }
  })
  return res
}

去重

1. Set

[...new Set[arr]]

2. 对象属性去重
function unique(arr) {
  let len = arr.length
  let res = []
  let obj = {}
  for (let i = 0; i < len; i++) {
    if (!obj.hasOwnProperty(arr[i])) {
      obj[arr[i]] = arr[i]
    }
  }
  return Object.values(arr)
}

3. indexOf
function unique(arr) {
  let res = []
  for (let i = 0; i < arr.length; i++) {
    if (res.indexOf(arr[i]) === -1) {
      res.push(arr[i])
    }
  }
  return res
}

Ajax

function request({ method, url, data = null, config: { headers = {}, timeout = 60 * 1000, async = true } }) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open(method, url, async)

    Object.entries(headers).forEach((headerArr) => {
      xhr.setRequestHeader(headerArr[0], headerArr[1])
    })

    xhr.send(data)
    xhr.timeout = timeout
    xhr.ontimeout = () => {
      reject()
    }

    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4) {
        const status = xhr.status
        if ((status >= 200 && status < 300) || status === 304) {
          resolve(xhr.responseText)
        } else {
          reject()
        }
      }
    }
  })
}

request({ method: 'POST', url: 'http://127.0.0.1:3000', config: { timeout: 10 * 1000 } })
  .then((res) => {
    console.log(res)
  })
  .catch((err) => {
    console.log(err)
  })

排序

稳定性:待排序的记录中,存在多个具有相同关键字的记录,经过排序后,这些记录的相对序列保持不变,则称算法是稳定的,否则是不稳定的

冒泡排序

function bubbleSort(arr) {
  let len = arr.length
  for (let i = 0; i < len - 1; i++) {
    for (let j = 0; j < len - i; j++) {
      if (arr[j] > arr[j + 1]) {
        let temp = arr[j]
        arr[j] = arr[j + 1]
        arr[j + 1] = temp
      }
    }
  }
  return arr
}

快排

function quickSort(arr) {
  _quickSort(arr, 0, arr.length - 1)
}
function _quickSort(arr, l, r) {
  if (l > r) return

  let left = l,
    right = r

  let base = arr[left]
  let temp
  while (l != r) {
    while (arr[r] >= base && l < r) {
      r--
    }
    while (arr[l] <= base && l < r) {
      l++
    }

    if (l < r) {
      temp = arr[l]
      arr[l] = arr[r]
      arr[r] = temp
    }
  }
  arr[left] = arr[l]
  arr[l] = base
  _quickSort(arr, left, l - 1)
  _quickSort(arr, l + 1, right)
}

归并排序

function mergeSort(arr) {
  _mergeSort(arr, 0, arr.length - 1)
}

function _mergeSort(arr, l, r) {
  if (l < r) {
    const mid = l + parseInt((r - l) / 2)
    _mergeSort(arr, l, mid)
    _mergeSort(arr, mid + 1, r)
    _merge(arr, l, mid, r)
  }
}

function _merge(arr, l, mid, r) {
  let i = l,
    j = mid + 1
  let k = 0,
    temp = []
  while (i <= mid && j <= r) {
    if (arr[i] > arr[j]) {
      temp[k++] = arr[j++]
    } else {
      temp[k++] = arr[i++]
    }
  }

  while (i <= mid) {
    temp[k++] = arr[i++]
  }

  while (j <= r) {
    temp[k++] = arr[j++]
  }
  for (let i = 0; i < k; i++) {
    arr[l + i] = temp[i]
  }
}

选择排序

function selectSort(arr) {
  let len = arr.length
  let temp, minIdx
  for (let i = 0; i < len - 1; i++) {
    minIdx = i
    for (let j = i + 1; j < len; j++) {
      if (arr[minIdx] > arr[j]) {
        minIdx = j
      }
    }
    temp = arr[minIdx]
    arr[minIdx] = arr[i]
    arr[i] = temp
  }
  return arr
}

插入排序

function insert(arr) {
  let len = arr.length
  for (let i = 0; i < len - 1; i++) {
    let preIdx = i
    let current = arr[i + 1]
    while (preIdx >= 0 && current < arr[preIdx]) {
      arr[preIdx + 1] = arr[preIdx]
      preIdx--
    }
    arr[preIdx + 1] = current
  }
  return arr
}

Last updated