自留

78 阅读6分钟

防抖节流

//防抖 适用于需要等待一段时间才能确保用户已经完成操作的场景 比如输入搜索
function debounce(func,delay,immediate){
    var timeout;
    return function(){
        var _this=this; //研究一下为什么等号后面的this是指向<div>的
        var e=arguments;//保存event对象
        if(timeout) clearTimeout(timeout);//用闭包来保存timeout的状态
        if(immediate){
            const callNow = !timeout;
            timeout = setTimeout(()=>{
                timeout = null;
            },delay)
            if(callNow) func.apply(_this,e);
        }else{
            timeout=setTimeout(function(){
                func.apply(_this,e);  //如果不加,getUserAction里面的this就会变成window
            },delay);
        }
    }
}
var throttle = (func, delay) => {
    let timeFlag=null, last=null;
    return function(){
        let _args = arguments;
        let _this = this;
        let now = +new Date();
        if(last&&last + delay > now){
            clearTimeout(timeFlag);
            timeFlag = setTimeout(() => {
                last = now;
                func.apply(_this,_args);
            },delay)
        }else{
            last = now;
            func.apply(_this,_args);
        }
    }
}

promiseAll & promiseRace

function promiseAll(promises) {
  var res = [],
    count = 0;
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      Promise.resolve(promises[i]).then(
        (v) => {
          count++;
          res[i] = v;
          if (count == promises.length) {
            resolve(res);
          }
        },
        (r) => {
          reject(r);
        }
      );
    }
  });
}
function promiseRace(promises) {
  return new Promise((resolve, reject) => {
    for (let i = 0; i < promises.length; i++) {
      promises[i].then(
        (v) => {
          resolve(v);
        },
        (r) => {
          reject(r);
        }
      );
    }
  });
}

发布订阅

class EventEmitter {
    constructor() {
      this.list = {}
    }
    //
    on(name, fn) {
      if (this.list[name]) {
        this.list[name].push(fn) 
      } else {
        this.list[name] = [fn] //如果直接赋值的话就不是一个数组了
      }
    }
    off(name, fn) {
      const tasks = this.list[name]
      if (tasks) {
        const index = tasks.findIndex((f) => f === fn || f.callback === fn)// 可以不写后面这个
        if (index >= 0) {
          tasks.splice(index, 1)
        }
      }
    }
    emit(name, once = false) {
      if (this.list[name]) {
        // 用slice的目的是创建副本,如果回调函数内继续注册相同事件,会造成死循环
        const tasks = this.list[name].slice();
        for (let fn of tasks) {
          fn();
        }
        if (once) {
          delete this.list[name] //delete是删除对象属性的
        }
      }
    }
  }

深拷贝

function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
  if (typeof obj !== "object") return obj;
  // 是对象的话就要进行深拷贝
  if (hash.get(obj)) return hash.get(obj); //解决循环引用
  let cloneObj = Array.isArray(obj) ? [] : {};
  hash.set(obj, cloneObj); //set的过程也是存的地址,改变newObj,hash里的值也会变
  for (let key in obj) {
    console.log(key)
    if (obj.hasOwnProperty(key)) {
      //确保这个属性不是原型上的
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}

柯里化 和下面那个不一样

function sum(x,y,z) {
    return x + y + z
}

function hyCurrying(fn) {
    // 判断当前已经接收的参数的个数,和函数本身需要接收的参数是否一致
    function curried(...args) {
        // 1.当已经传入的参数 大于等于 需要的参数时,就执行函数
        if(args.length >= fn.length){
            // 如果调用函数时指定了this,要将其绑定上去
            return fn.apply(this, args)
        }
        else{
            // 没有达到个数时,需要返回一个新的函数,继续来接收参数
            return function(...args2) {
                //return curried.apply(this, [...args, ...args2])
                // 接收到参数后,需要递归调用 curried 来检查函数的个数是否达到
                return curried.apply(this, args.concat(args2))
            }
        }
    }
    return curried
}

var curryAdd = hyCurry(sum)

curryAdd(10,20,30)
curryAdd(10,20)(30)
curryAdd(10)(20)(30)

add(1, 2)(3, 4, 5)(6)

function curry(...args) {
  // 保存预置参数
  function curried (...restArgs) {
    return curry(...args,...restArgs)
  }
  curried.toString = function() {
    let fn = args[0]
    let param = args.slice(1)
    return fn(...param)
  }
  return curried;
}
let dynamicAdd = (...args) => args.reduce((prev, curr) => prev + curr, 0)
var add = curry(dynamicAdd);
console.log(Number(add(1, 2)(3, 4,5)(6))) // 21

数组转树 不止一个父节点的情况

let list = [
  { id: 56, parent_id: 62 },
  { id: 81, parent_id: 80 },
  { id: 74, parent_id: null },
  { id: 76, parent_id: 80 },
  ......
];
function fn(list) {
  let obj = {};
  let res = [];
  for (let item of list) {
    obj[item.id] = item;
  }
  for (let item of list) {
    if (obj[item.parent_id]) {
      if(!obj[item.parent_id].children){
        obj[item.parent_id].children=[]
      }
      obj[item.parent_id].children.push(item)
    } else {
      res.push(item);
    }
  }
  return res;
}

数组拍平和去重

去重 拍平

instanceof

function new_instance_of(leftVaule, rightVaule) { 
    let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
    leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
    while (true) {
    	if (leftVaule === null) {
            return false;	
        }
        if (leftVaule === rightProto) {
            return true;	
        } 
        leftVaule = leftVaule.__proto__ 
    }
}

deepEqual

function isEqual(x, y) {
  if (x === y) {
    return true;
  } else if (
    typeof x === "object" &&
    x !== null &&
    typeof y === "object" &&
    y !== null
  ) {
    const keysX = Object.keys(x);
    const keysY = Object.keys(y);
    if (keysX.length !== keysY.length) {
      return false;
    }
    for (const key of keysX) {
      if (!isEqual(x[key], y[key])) {
        return false;
      }
    }
    return true;
  } else {
    return false;
  }
}

bind apply call

Function.prototype._call = function(thisArg,...args){
    // 1.获取需要执行的函数
    let func = this
    // 2.将 thisArg 转成对象类型(防止它传入的是非对象类型,例如123数字)
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
    // 3.使用 thisArg 调用函数,绑定 this
    // 用 Symbol 创建一个独一无二的属性,避免属性覆盖或冲突的情况
    let fn = Symbol()
    thisArg[fn] = this
    // thisArg.fn = fn
    let result = thisArg[fn](...args)
    delete thisArg[fn]
    // 4.返回结果
    return result
}

Function.prototype._apply = function(thisArg,argArray){
    // 1.获取需要执行的函数
    let fn = this
    // 2.将 thisArg 转成对象类型(防止它传入的是非对象类型,例如123数字)
    thisArg = (thisArg !== null && thisArg !== undefined) ? Object(thisArg) : window
    // 判断一些边界情况
    argArray = argArray || []
    // 3.使用 thisArg 调用函数,绑定 this
    thisArg.fn = fn
    // 将传递过来的数组(可迭代对象)拆分,传给函数
    let result = thisArg.fn(...argArray)
    delete thisArg.fn
    // 4.返回结果
    return result
}

Function.prototype._bind = function(thisArg,...args){
    let fn = this // 需要调用的那个函数的引用
    // bind 需要返回一个函数
    return function(){
        return fn._call(thisArg, ...args)
    }
}

setTimeout实现setInterval

function setInterval(fn, time){
    var interval = function(){
    // time时间过去,这个异步被执行,而内部执行的函数正是interval,就相当于进了一个循环
        setTimeout(interval, time);
    // 同步代码
        fn();
    }
    //interval被延迟time时间执行
    setTimeout(interval,time); 
}

实现new

function myNew(){
    //1.创建一个新的对象
    let obj = {};
    //获得构造函数
    let con = [].shift.call(arguments); 
    //2.新对象的隐式原型__proto__链接到构造函数的显式原型prototype
    obj.__proto__ = con.prototype;
    //3.构造函数内部的 this 绑定到这个新创建的对象 执行构造函数
    let result = con.apply(obj, arguments)
    //4.如果构造函数没有返回非空对象,则返回创建的新对象
    return result instanceof Object ? result:obj;
}
// test
function Car(name,price){
    this.name = name 
}
Car.prototype.run = function() {
    console.log(this.price);
};
var test_create = myNew(Car, 'a', 100000);
console.log(test_create)
// compare
let obj = new Car( 'a', 100000)
console.log(obj)

实现并发

// 请求大量url,限制同时存在的请求数为5个。
const limitMessages = (urls ,limit) => {
    let count = 0;
    let lens = urls.length;
    const pooling = (url) => {
      sendMessage(url).then((v) => {
        console.log(`request ${v} finished`);
        if(++count < lens){
          pooling(urls[count]);
        }
      })
    }
    for(let i = 0 ; i < limit ; i++){
      pooling(urls[count++]);
    }
  }
  const sendMessage = (url) => {
    return new Promise((resolve) => {
      console.log(`start request ${url}`);
      setTimeout(() => {
        resolve(url);
      },Math.random()*10000);
    })
  }
  let urls = Array.from(new Array(100).keys())
  limitMessages(urls,5)
  let solve = (urls,limits) =>{
    let count = 0
    for(let i = 0; i<limits; i++){
      pooling();
    }
    let pooling = ()=>{
      sendMessage(urls[count++]).then(r => {
        if(count < urls.length){
          poopling();
        }
      })
    }
  }

hardman

class _HardMan {
    constructor(name) {
        this.tasks = [];
        // 主要是考虑了restFirst的情况,这样可以使得所有的任务入队以后,才开始执行第一个next函数
        setTimeout(async () => {
            for (let task of this.tasks) {
                await task() // task有可能是异步任务所以要用await和async
            }
        })
        this.tasks.push(() =>   //必须是promise,因为上面的await,包括下面的learn也得是promise
            new Promise(resolve => {
                console.log(`I am ${name}`)
                resolve()
            })
        )
    }
    wait(sec) {
        return new Promise(resolve => {
            setTimeout(() => {
                console.log(`Start learning after ${sec} seconds`)
                resolve()
            }, sec * 1000);
        })
    }
    rest(sec) {
        this.tasks.push(() => this.wait(sec))
        return this
    }
    restFirst(sec) {
        this.tasks.unshift(() => this.wait(sec))
        return this
    }
    learn(params) {
        this.tasks.push(() =>
            new Promise(resolve => {
                console.log(`Learning ${params}`)
                resolve()
            })
        )
        return this
    }
}
const HardMan = function (name) {
    return new _HardMan(name)
}
// 这里是外部代码属于宏任务,只有等这里执行完了才会执行下一个宏任务即settimeout
HardMan("jack").restFirst(3).learn("Chinese").learn("Englsih").rest(2).learn("Japanese")
/*
Start learning after 3 seconds
I am jack
Learning Chinese
Learning Englsih
Start learning after 2 seconds
Learning Japanese
*/