美文网首页
JavaScript编码能力篇

JavaScript编码能力篇

作者: 阿羡吖 | 来源:发表于2020-04-27 13:59 被阅读0次

    1.多种方式实现数组去重,扁平化、对比优缺点

    数组去重

    var arr =[1,43,2,4,5,7,4,2,3,8]
    //去重去
    arr = [1,43,2,4,5,7,3,8]

    传统方式,for循环实现

    function dedupe(arr){
      var rets = [];
      for(var i =0; i<arr.length;i++){
        if(!rets.includes(arr[i])){
          rets.push(arr[i])
        }
      }
      return rets
    }
    //方法二:forEach方法实现
    function dedupe(arr){
       var rets = [],obj ={};
       arr && arr.forEach(function(item){
          if(!obj[item]){
                obj[item]=item;
                 rets.push(item);
               }
         })
             return rets
        }
    

    ES6方法实现

    //es6提供的新的数据结构Set,类似数组,但是成员的值都是唯一的,没有重复值。
    function dedupe(arr){
      var newSet = new Set(arr); //arr变成了set的数据结构,并去除了其中重复的元素
      return Array.from(newSet);//Array.from方法将set数据结构转为数组结构 
    }
    

    复杂数据结构的数组去重

    [1,2,{a:1},3,2,{a:1},[1,2],[1,2]] //数组中的元素包含对象和数组

    function unique(arr){
     const hash ={};
     const res = [];
     for(let i =0;i<arr.length;i++){
       if(hash[arr[i]] == null){
          res.push(arr[i])
          hash(arr[i]) = true
        }  
     }
     return res
    }
    unique([1,2,{a:1},3,2,{a:1},[1,2],[1,2]])
    // 1,2,{a:1},3,[1,2]
    
    数组扁平化

    数组的扁平化,就是将一个嵌套多层的数组array(嵌套可以使任何层数)转换为只有一层的数组

    var arr =[1,2,3,[4,3,[2,7],2],5[5,9,10],7];
    //去扁平化后
    arr = [1,2,3,4,3,2,7,2,5,5,9,10,7]

    循环递归实现

    // for循环 如果子元素还是数组,则递归调用该方法
    function flatten(arr){
      var rets = [];
      for(var i =0; i<arr.length;i++){
        if(Array.isArray(arr[i])){
          rets = rets.concat(flatten(arr[i]))
        }else{
          rets.push(arr[i])
        }
      }
      return rets;
    }
    
    // 使用forEach
    function flatten(arr){
      var rets = [];
      arr && arr.forEach(function(item) =>{
        if(Array.isArray(item)){
          rets = rets.concat(flatten(item));
        }else{
          rets.push(item)
        }
      })
      return rets;
    }
    

    使用reduce简化代码

    function flatten(arr){
      return arr.reduce(function(pre,item){
        return pre.concat(Array.isArray(item)?flatten(item):item);
      },[])
    }
    

    如果数组元素为数字,则可以使用toString方法。

    function flatten(arr){
      var newArr = arr.toString().split(',');
      return newArr.map(function(item){
        return + item //将字符串转为数字
      })
    }
    

    2.多种方式实现深拷贝、对比优缺点

    如何区分深拷贝和浅拷贝
    简单来说,就是假设B复制了A ,当修改A时,看B是否发生变化,如果B跟着变,说明是浅拷贝。反之,B没变,那就是深拷贝。

    (1)递归
    function deepClone(obj){
      let objClone = Array.isArray(obj)?[]:{};
      if(obj && typeof obj === "object"){
        for(key in obj){
          if(obj.hasOwnProperty(key)){
            //判断ojb子元素是否为对象,如果是,递归复制
            if(obj[key]&& typeof[key] === "object"){
              objClone[key] = deepClone(obj[key])
            }else{
              //如果不是 简单复制
              objClone[key] = obj[key]
            }
          }
        }
      }
      return objClone
    }
    let a =[1,2,3,4];
    b =deepClone(a);
    a[0] = 2;
    console.log(a,b)
    
    (2)借用JSON对象的parse和stringify
    function deepClone(obj){
      let _obj = JSON.stringify(obj),
      objClone = JSON.parse(obj);
      return objClone
    }
    let a =[0,1,[2,3],4],
    b = deepClone(a);
    a[0] =1;
    a[2][0] = 1;
    console.log(a,b)
    
    (3)借用JQ的extend方法
    $.extend([deep],target,object1[,objectN])
    //deep 表示是否深拷贝,true为深拷贝,false 为浅拷贝
    // target Object 类型目标对象,其他对象的成员属性将被附加到该对象上
    object1 objectN可选。 Object类型 第一个以及第一N个被合并的对象。
    let a = [0,1,[2,3],4],
    b=$.extend(true,[],a);
    a[0] =1;
    a[2][0] = 1;
    console.log(a,b)
    

    3.手写函数柯里化工具函数、并理解其应用场景和优势

    简单来说,就是固定一些参数,返回一个接受剩余参数的函数
    其实就是使用闭包返回一个延迟执行函数

    //这个例子是柯里化,也可以说是部分应用
    function add(num1,num2){
      return num1 + num2
    }
    function curry(func){
      let args = [] .slice.call(arguments,1);
      return function(){
        let innerArgs = [] .slice.call(arguments)
        let finalArgs = [...args,...innerArgs];
        return func.apply(null,finalArgs)
      }
    }
    // 得到延迟执行函数
    let curriedAdd = curry(add,5)
    // 可以多次复用得到的函数
    curriedAdd(1);  // 6
    curriedAdd(2); //7
    

    下面再来实现curriedAdd(1)(2,3)(4)的柯里化函数

    function aidCurry(func){
      let args = [] .slice.call(arguments,1);
      return function(){
        return func.apply(null,[...arge,...arguments]); 
      }
    }
    function curry(func,length){
      length = length || func.length
      return function(){
        //传入参数为0 表示返回结果
        if(arguments.length !=0 && arguments.length < length){
          let finalArgs = [func, ...arguments];
          // 参数的数量不足时,利用闭包将已传入参数存起来
            return curry(aidCurry.apply(null,finalArgs),length-arguments.length);
        }else{
          //参数数量足够了或者中途结束,则返回结果
          return func.apply(null,arguments);
        }
      };
    }
    // length 为4 表示当传入参数达到4个时返回结果
    let curriedAdd = curry(function add){
      retutrn [...arguments].reduce((acc,cur) => acc + cur);
    },4);
    // 传入参数为4个
    curriedAdd(1),(2,3)(4); // 10
    //中途结束
    curriesAdd(1)(2,3)()  // 6
    //error:not a function
    curriedAdd(1)(2)()(3);//使用() 就表示返回结果已经不是函数
    curriedAdd(1))(2,3)(4)(); //传入参数已经为4个,所以返回结果了 已经不是函数
    

    4.手写防抖和节流工具函数、并理解其内部原理和应用场景

    防抖函数

    什么是函数防抖
    函数防抖:就是指触发事件后,在n秒内函数只能执行一次,如果触发事件后在n秒内又触发了事件,则会重新计算函数延迟执行之间。

    为什么需要做函数防抖
    前端开发中,有一些时间事件,常见用onresize scroll mousemove mpusehover等等,会被频繁触发,如不作限制的话,有可能一秒之内执行很多次,如果在这些函数内部执行了其他函数,尤其是执行对DOM 操作的函数,那不仅会浪费资源,还会降低程序运行速度,甚至造成浏览器卡死、崩溃,这些问题显然是致命的。

    函数防抖如何解决上述问题
    函数防抖的重点,是一个需要setTimeout 来辅助实现,延迟需要执行的代码,如果方法多次触发,则把上次记的延迟执行代码clearTimeout清掉,重新开始计时。若计时期间事件没有被重新触发,等延迟时间结束,则执行目标代码。

    函数防抖代码实现

    function debouce(fn,wait){
      var timer = null;
      return function(){
        if(timer != null){
          clearTimeout(timer)
        }
        timer = setTimeout(fn,wait);
      }
    }
    function handle(){
      console.log(Math.random())
    }
    window.addEventListener('resize',debounce(handle,1000))
    
    函数节流

    什么是函数节流
    限制一个函数在一定时间段内只能执行一次

    为什么需要函数节流
    同函数防抖

    函数节流代码实现

    // 时间戳方案
    function throttle(fn,wait){
      var pre = Date.now();
      return function(){
        var contect = this;
        var args = arguments;
        var now = Date.now();
        if(now - pre > = wait){
          fn.apply(context,args);
          pre = Date.now();
        }
      }  
    }
    function handle(){
      console.log(Math.random());
    }
    window.addEventListener('mousemove',throttle(handle,1000));
    
    // 定时器方案
    function throttle(fn,wait){
      var timer = null;
      return function(){
        var context = this;
        var args = arguments;
        if(!timer){
          timer = setTimeout(function(){
            fn.apply(context,args);
            timer = null
          },wait)
        }
      }
    }
    function handle(){
      console.log(Math.random())
    }
    window.addEventListener('mousemove',throttle(handle,1000));
    

    函数节流的使用场景
    1、懒加载,滚动加载,加载更多或监听滚动条的位置
    2、百度搜索框,搜索联想功能
    3、防止高频点击提交、防止表单重复提交

    5.实现一个sleep函数

    // 方法一
    function sleep1(ms,callback){
      setTimeout(callback,ms)
    }
    // sleep 1s
    sleep1(1000,()=>{
      console.log(1000)
    })
    //方法二
    function sleep2(ms){
      return new Promise(function(resolve,reject){
        setTimeout(resolve,ms) 
      })
    }
    sleep2(1000).then(() =>{
      console.log(2000)
    })
    //方法三:
    function sleep3(ms){
      return new Promise(function(reslove,reject){
        setTimeout(reslove,ms)
      })
    }
    
    asyns function init(){
      await sleep3(1000)
    }
    init().then(() =>{
      console.log(3000)
    })
    

    相关文章

      网友评论

          本文标题:JavaScript编码能力篇

          本文链接:https://www.haomeiwen.com/subject/snidwhtx.html