实现几个js小工具

101 阅读3分钟

深拷贝

function deepClone(obj) {
    // 如果是 值类型 或 null,则直接return
    if(typeof obj !== 'object' || obj === null) {
        return obj
    }
    
    // 定义结果对象
    let copy = {}
    
    // 如果对象是数组,则定义结果数组
    if(obj.constructor === Array) {
        copy = []
    }
    
    // 遍历对象的key
    for(let key in obj) {
        // 如果key是对象的自有属性
        if(obj.hasOwnProperty(key)) {
            // 递归调用深拷贝方法
            copy[key] = deepClone(obj[key])
        }
    }
    
    return copy
}

防抖和节流

// 实现 debounce(防抖)函数
function debounce(fn,time){
    let timer=null
    return function(){
        clearInterval(timer)
        timer=setTimeout(()=>{fn.apply(this,arguments)},time)
    }
}

// 实现截节流函数
function throttle(fn,time){
    let flag=true
    return function(){
        if(!flag) return
        flag=false
        setTimeout(()=>{
            fn.call(this,arguments)
            flag=true
        },time)


    }
}

实现一个对象的 flatten 方法

const obj = {
	a: {
  	b: 1,
	c: 2,
	d: {
		e: 5
	}
  },
  b: [1, 3, {a: 2, b: 3}],
  c: 3
}
flatten(obj) // 结果返回如下

{
  'a.b': 1,
  'a.c': 2,
  'a.d.e': 5,
  'b[0]': 1,
  'b[1]': 3,
  'b[2].a': 2,
  'b[2].b': 3
   c: 3
}


function flat(obj,key,res={},isArray=false){
    for(let [k,v] of Object.entries(obj)){
        if(Array.isArray(v)){
            let tmp=isArray?key+'['+k+']'+k:key+k
            flat(v,tmp,res,true)
        }else if(typeof v==='object'){
            let temp=isArray?key+'['+k+']'+'.':key+k+'.'
            flat(v,tmp,res,false)
        }else{
            let tmp=isArray?key+'['+k+']':key+k
            res[tmp]=v
        }
    }
    return res
}

实现instanceof

const myInstanceof=function(left,right){
    if(typeof left !=='object' || left===null) return false
    const proto=Object.getPrototypeOf(left)
    while(true){
        if(proto===null) return false
        if(proto===right.prototype) return true
        proto=Object.getPrototypeOf(proto)
    }
}

柯里化求值

// 实现一个柯里化函数add
const sum1=add(1)(2)(3)(4)
console.log(sum1+'');
// function add1(args){
//     return fn(args,)
// }

// add(1)(1,2,3)(2)=9;
function add(){
    const args=[...arguments]
    function fn(){
        args.push(...arguments)
        return fn
    }
    fn.toString=function(){
        return args.reduce((sum,cur)=>sum+cur)
    }
    return fn
}

// 普通函数转化为柯里化函数求值

// 分批传入参数
// redux 源码的compose也是用了类似柯里化的操作
// 分批传入参数
// redux 源码的compose也是用了类似柯里化的操作
const curry = (fn, arr = []) => {// arr就是我们要收集每次调用时传入的参数
    let len = fn.length; // 函数的长度,就是参数的个数
    // debugger
    return function(...args) {
      let newArgs = [...arr, ...args] // 收集每次传入的参数
        // debugger
      // 如果传入的参数个数等于我们指定的函数参数个数,就执行指定的真正函数
      if(newArgs.length === len) {
        return fn(...newArgs)
      } else {
        // 递归收集参数
        return curry(fn, newArgs)
      }
    }
  }

  function sum(a,b,c,d,e) {
    return a + b + c + d + e
  }
  
  // 传入指定的函数,执行一次
  let newSum = curry(sum)
  
  // 柯里化 每次入参都是一个参数
  // const res1=newSum(1)(2)(3)(4)(5)
  
  // 偏函数
  const res2=newSum(1)(2)(3,4,5)

用setTimeOut实现setInterval

// 用setTimeOut实现setInterval
// 思路是使用递归函数,不断地去执行 setTimeout 从而达到 setInterval 的效果

function mySetInterval(fn, timeout) {
    // 控制器,控制定时器是否继续执行
    var timer = {
      flag: true
    };
  
    // 设置递归函数,模拟定时器执行。
    function interval() {
      if (timer.flag) {
        fn();
        setTimeout(interval, timeout);
      }
    }
  
    // 启动定时器
    setTimeout(interval, timeout);
  
    // 返回控制器
    return timer;
  }
  

实现jsonp

function jsonp(url, params, callback) {
    // 判断是否含有参数
    let queryString = url.indexOf("?") === "-1" ? "?" : "&";
  
    // 添加参数
    for (var k in params) {
      if (params.hasOwnProperty(k)) {
        queryString += k + "=" + params[k] + "&";
      }
    }
  
    // 处理回调函数名
    let random = Math.random()
        .toString()
        .replace(".", ""),
      callbackName = "myJsonp" + random;
  
    // 添加回调函数
    queryString += "callback=" + callbackName;
  
    // 构建请求
    let scriptNode = document.createElement("script");
    scriptNode.src = url + queryString;
  
    window[callbackName] = function() {
      // 调用回调函数
      callback(...arguments);
  
      // 删除这个引入的脚本
      document.getElementsByTagName("head")[0].removeChild(scriptNode);
    };
  
    // 发起请求
    document.getElementsByTagName("head")[0].appendChild(scriptNode);
  }

手写一个new

function mynew(Func, ...args) {
    // 1.创建一个新对象
    const obj = {}
    // 2.新对象原型指向构造函数原型对象
    obj.__proto__ = Func.prototype
    // 3.将构建函数的this指向新对象
    let result = Func.apply(obj, args)
    // 4.根据返回值判断
    return result instanceof Object ? result : obj
}

实现数字的千分位逗号分割



function thousands(num) {
    var result = [], counter = 0;
    num = (num || 0).toString().split('');
    for (var i = num.length - 1; i >= 0; i--) {
        counter++;
        result.unshift(num[i]);
        if (!(counter % 3) && i != 0) { result.unshift(','); }
    }
    console.log(result.join(''));
}

thousands(314159265354)