2020js手写系列

205 阅读3分钟

冒泡排序

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

非原地快排

    function quickSort(arr) {
        if(arr.length <= 1) return arr
        let arr1 = [], arr2 = [], p = arr[0]
        for(let i=1;i<arr.length;i++) {
            if(arr[i] < p) {
                arr1.push(arr[i])
            } else {
                arr2.push(arr[i])
            }
        }
        let res = [...quickSort(arr1), p, ...quickSort(arr2)]
    }

工厂模式

function Product(name) {
  this.name = name;
}
Product.prototype.init = function () {
  console.log('init');
}
Product.prototype.go = function () {
  console.log('go');
}

function Factory () {
}
Factory.prototype.add = function(name) {
  return new Product(name);
}

//use
let f = new Factory();
let a = f.add('a');

console.log(a.name);
a.init();
a.go();

发布订阅模式

    class Event {
        constructor() {
           this.listener = {

           }
        }
        on(name, cb) {
            if(!this.listener[name]) {
                this.listener[name] = []
            }
            this.listener[name].push(cb)
        }
        emit(name) {
            for(let key of this.listener[name]) {
                key()
            }
        }
    }

单例模式

    class singleDog {
        static getInstance() {
            if(!singleDog.instance) {
                singleDog.instance = new singleDog()
            }
            return singleDog.instance
        }
    }

instanceof

  function instanceOf(obj, Constructor) {
    let proto = obj.__proto__
    while (proto !== Constructor.prototype) {
      if(proto === null) return false
      proto = proto.__proto__
    }
    return true
  }

防抖

function debounce(fn) {
      let timeout = null; // 创建一个标记用来存放定时器的返回值
      return function () {
        clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉
        timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
          fn.apply(this, arguments);
        }, 500);
      };
    }
    function sayHi() {
      console.log('防抖成功');
    }

    var inp = document.getElementById('inp');
    inp.addEventListener('input', debounce(sayHi)); // 防抖

节流

function throttle(fn) {
      let canRun = true; // 通过闭包保存一个标记
      return function () {
        if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return
        canRun = false; // 立即设置为false
        setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中
          fn.apply(this, arguments);
          // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉
          canRun = true;
        }, 500);
      };
    }
    function sayHi(e) {
      console.log(e.target.innerWidth, e.target.innerHeight);
    }
    window.addEventListener('resize', throttle(sayHi));

call

 Function.prototype.mycall = function(context) {
 	if(typeof this !== 'function') {
    	throw new Error('error')
    }
    context = context || window
    let args = [...arguments].slice(1)
    context.fn = this
    const res = context.fn(...args)
    delete context.fn
    return res
 }

apply

 Function.prototype.apply = function(context) {
   if(typeof this !== 'function') {
     throw new Error('error')
   }
   context = context || window
   context.fn = this
   let res
   if(arguments[1]) {
     res = context.fn(...arguments[1])
   }else {
     res = context.fn()
   }
   delete context.fn
   return res
 }

完整且简洁bind

Function.prototype.mybind = function(context) {
	if(typeof this !== 'function') {
    	throw new Error('error')
    }
    const _this = this
    const args = [...arguments].slice(1)
    return function F(){
    	if(_this instanceof F) {
        	return new _this(...args,...argument)
        }
        return _this.apply(context,args.concat(argument))
    }
}

bind

简单bind

  Function.prototype.mybind = function(THIS,...arg1) {
    let fn = this // 哪个函数调用bind
    return function(...arg2) {
      return fn.call(THIS,...arg1,...arg2)
    }
  }
  function sum(a,b,c) {
    return a + b + c
  }
  let sum10 = sum.bind(null,10)
  console.log(sum10(20,30));

进阶bind

  Function.prototype.mybind = function(THIS,...arg1) {
    let fn = this // 哪个函数调用bind
    function T(...arg2) {
      return fn.call(THIS,...arg1,...arg2)
    }
    T.prototype = Object.create(fn.prototype)
    return T
  }
  function sum(a,b,c) {
    return a + b + c
  }
  let sum10 = sum.bind(null,10)
  console.log(sum10(20,30));

bind完成版

  Function.prototype.mybind = function(THIS,...arg1) {
    let fn = this // 哪个函数调用bind
    function T(...arg2) {
      return fn.call(this instanceof T ? this : THIS,...arg1,...arg2)
    }
    T.prototype = Object.create(fn.prototype)
    return T
  }
  function sum(a,b,c) {
    return a + b + c
  }
  let sum10 = sum.bind(null,10)
  console.log(sum10(20,30));

new

    function myNew(fn, ...args) {
        let obj ={}
        obj = Object.create(fn.prototype)
        let res = fn.apply(obj, args)
        return res instanceof Object ? res : obj
    }

Object.create

  function create(o) {
    let obj = {}
    Object.setPrototypeOf(obj, o)
    return obj
  }

sleep

  function sleep(t) {
    return new Promise((resolve,reject) => {
      setTimeout(() => {
        resolve()
      },t)
    })
  }
  await sleep(1000)

遍历DOM树

//dom树
function Tree() {
      
      var Node = function(key){
            this.key = key;
            this.left = null;
            this.right = null;
      }
    
     root =null;

前序遍历

Tree.prototype.preOrderTraverse = function(callback){
    preOrder(root, callback);
}
var preOrder = function(node,callback){
    if(node !== null){
        callback(node.key);
        preOrder(node.left, callback);
        preOrder(node.right, callback);
    }
}

promise

  function MyPromise(fn) {
    let self = this
    self.value = null
    function onResolve(value) {
      console.log(value);
      self.value = value
    }
    function onReject(reason) {}
    fn(onResolve, onReject)
  }
  MyPromise.prototype.then = function(fn) {
    fn(this.value)
  }
  new MyPromise((resolve,reject) => {
    resolve(1000) 
  })
  .then(r => {
    console.log(r);
  })

更完整的promise

  function MyPromise(fn) {
    let self = this;
    this.value = undefined;
    this.status = 'PENDING';
    function onResolve(value) {
      // console.log(value);
      self.status = 'FULFILLED';
      self.value = value;
      self.onFulFilled && self.onFulFilled(value);
    }  // 定义 什么时候执行
    function onReject(reason) {}
    fn(onResolve, onReject);
  }
  MyPromise.prototype.then = function(fn) {
    if (this.status === 'FULFILLED') fn(this.value);
    // 
    else if (this.status === 'PENDING') this.onFulFilled = fn;
    
  }
  new MyPromise((resolve, reject) => {
    setTimeout(() => {
      resolve(1000);
    }, 1000)  // 改变状态的时候 
  })
  .then(r => {
    console.log(r)
  })


  function readFile(fn) {
  // 
    fn('hello world')
  }
  readFile((r) => {
    console.log(r); // hello world
  })

promise.all

    Promise.myAll = function(promiseArr) {
      return mewPromise((resolve, reject) => {
        let res = [], count = 0
        for(let i = 0;i < promiseArr.length; i++) {
          promiseArr[i].then((r) => {
            res[i] = r
            count++
            if(count === promiseArr.length) {
              resolve(res)
            }
          })
          .catch(() => {
            reject()
          })
        }
      })
    }

promise 限制并发

  Promise.limitAll = function (promiseCreators, max) {
    let i = 0, count = 0, pending = 0, res = [];
    return new Promise((resolve, reject) => {
      function requestWork() {
        if (count >= promiseCreators.length) {
          resolve(res);
          return;
        }
        while (pending < max && i < promiseCreators.length) {
          const creator = promiseCreators[i];
          let index = i;
          creator().then((r) => {
            console.log(r);
            pending--;
            count++;
            res[index] = r;  // 
            requestWork();
          })
          i++;
          pending++;
        }
      }
      requestWork();
    })
  }

深度遍历

let deepTraversal1 = (node, nodeList = []) => {
  if (node !== null) {
    nodeList.push(node)
    let children = node.children
    for (let i = 0; i < children.length; i++) {
      deepTraversal1(children[i], nodeList)
    }
  }
  return nodeList
}

广度遍历

let widthTraversal2 = (node) => {
  let nodes = []
  let stack = []
  if (node) {
    stack.push(node)
    while (stack.length) {
      let item = stack.shift()
      let children = item.children
      nodes.push(item)
        // 队列,先进先出
        // nodes = [] stack = [parent]
        // nodes = [parent] stack = [child1,child2,child3]
        // nodes = [parent, child1] stack = [child2,child3,child1-1,child1-2]
        // nodes = [parent,child1,child2]
      for (let i = 0; i < children.length; i++) {
        stack.push(children[i])
      }
    }
  }
  return nodes
}

原地快排

const quickSort = (arr, i, j) => {
        if(i >= j) return;
        let left = i, right = j, base = arr[left];
        while(left < right){
            while(arr[right] >= base && left < right){
                right --;
            }
            arr[left] = arr[right];
            while (arr[left] <= base && right > left){
                left ++;
            }
            arr[right] = arr[left];
        }
        arr[left] = base;
        quickSort(arr, i, left-1);
        quickSort(arr, left+1, j);
      }
      quickSort(arr,0,arr.length-1)

defineProperty

var data = {
  name: 'yuanlong'
}
observe(data)
let name = data.name
data.name = 'jinlong'

function observe(obj) {
  Object.keys(obj).forEach(key => {
    definReactive(obj,key,obj[key])
  })
}

function definReactive(obj, key, val) {
  if(typeof val === 'object' && val !== null) {
    observe(val)
  }
  Object.defineProperty(obj,key, {
    get: function() {
      return val
    },
    set: function(newVal) {
      val = newVal
    }
  })
}

柯里化

 function curry(fn) {
    let len = fn.length, args = [];
    function T(...arg) {
      args = args.concat(arg);
      if (args.length >= len) {
        let res = fn(...args);
        args = [];
        return res;
      } else {
        return T;
      }
    }
    return T;
  }
    function curry(fn) {
        let allArgs = []
        return function next(arguments) {
            if(arguments) {
                allArgs = allArgs.concat(arguments)
                return next
            } else {
                fn.apply(null, allArgs)
            }
        }
    }

深拷贝

    function deepClone(obj) {
        var newObj = obj instanceof Array ? [] : {};
        if (newObj instanceof Array) {
            obj.forEach((v, i) => {
                newObj[i] = typeof obj[i] === 'object' ? deepClone(v) : v
            })
        } else {
            for (var item in obj) {
                newObj[item] = typeof obj[item] == 'object' ? deepClone(obj[item]) : obj[item]
            }
        }
        return newObj;
    }

寄生组合继承

<script>
   // 寄生组合继承
   function Parent(name) {
      this.name = name
   }
   Parent.prototype.sayName = () => {
      console.log(this.name);
   }
   function Son(age) {
      this.age = age
      Parent.call(this)
   } 
   Son.prototype.sayAge = () => {
      console.log(this.age);
   }
   Son.prototype = Object.create(Parent.prototype)
</script>

手写reduce

   Array.prototype.myReduce = function(fn, init = this[0]) {
      for(let i=0;i<this.length;i++) {
         let current = this[i]
         init = fn(init, current, i, this)
      }
      return init
   }
   let myres =  arr.myReduce((pre, current,index, arr)=>{
      console.log(pre, current, index, arr);
      return pre += current
   }, 0)
   console.log(myres);