美文网首页
手写代码系列(持续更新)

手写代码系列(持续更新)

作者: Splendid飞羽 | 来源:发表于2021-05-23 15:21 被阅读0次

    一、JS常见代码手写

    1、手写instanceOf的实现原理
    function instanceOf(left, right){
      while(true){
         if(left === null) return false;
         if(left == right.prototype) return true;
         left = left.__proto__;
      }
    }
    
    2、手写节流和防抖函数

    2.1 节流函数

    节流函数原理:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效

    // 使用时间戳方案
    let throttle = function(fn, wait) {
        let lastTime = 0;
        return function(...args) {
            let nowTime = new Date();
            if (nowTime - lastTime > wait) {
                lastTime = nowTime;
                fn.apply(this, args);
            }
        }
    }
    
    function handle() {
        console.log(1);
    }
    
    window.addEventListener('mousemove', throttle(handle, 1000))
    
    

    2.2 防抖函数

    防抖函数原理:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时

    //2、使用定时器触发
    let throttle = function(fn, wait) {
        let timer = null;
        return function(...args) {
            if (!timer) {
                timer = setTimeout(() => {
                    fn.apply(this, args);
                    timer = null;
                    clearTimeout(timer);
                }, wait)
            }
        }
    }
    
    function handle() {
        console.log(1);
    }
    
    window.addEventListener('mousemove', throttle(handle, 1000))
    

    适用场景:

    拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
    缩放场景:监控浏览器resize
    动画场景:避免短时间内多次触发动画引起性能问题

    3、手写promise.all实现原理

    Promise.all() 方法接收一个promise的iterable类型,接收的是Promise对象的数组作为参数。当数组中所有的Promise对象全部变成Resovled状态,则整个Promise.all()也是Resolved状态

    Promise.all = function(arr){
       return new Promise((resolve, reject) => {
           if(!Array.isArray(arr)){
                return reject('arguments must be an array!')
           }
           let len = arr.length, resolveNum = 0, resolveRes = [];
           for(let i =0; i< len; i++){
               arr[i].then(data => {
                   resolveNum++;
                   resolveRes.push(data);
                   if(resolveNum == len){
                      return resolve(resolveRes);
                   }
               }).catch(err => {
                    return reject(err);
               })
           }
       })
    }
    //测试, 利用setTimeOut模拟异步操作
    var p1 = (function(){
      return new Promise((resolve, reject) => {
         setTimeout(() => resolve('p1')), 100}
      )
    })();
    var p2 = (function(){
      return new Promise((resolve, reject) => {
         setTimeout(() => resolve('p2')), 200}
      )
    })();
    
    Promise.all([p1, p2]).then(data => console.log(data))  // [p1, p2]
    
    4、手写nextTick的实现原理
    5、手写new操作

    new操作符做了这些事:

    创建一个全新的对象
    这个对象的proto要指向构造函数的原型prototype
    执行构造函数,使用 call/apply 改变 this 的指向
    返回值为object类型则作为new方法的返回值返回,否则返回上述全新对象js

    function myNew(fn, ...args) {
        let instance = Object.create(fn.prototype);
        let res = fn.apply(instance, args); // 改变this指向
    
        // 确保返回的是一个对象(万一fn不是构造函数)
        return typeof res === 'object' ? res: instance;
    }
    

    二、 DOM相关代码手写

    1、addClassName操作
    function addClassName(node, className){
        if(!className) return;
       let tempName = node.className + ' ' + className;
       node.className = tempName.replace(/\s+|\s$/, '');
    }
    
    2、removeClassName操作
    function removeClassName(node, className){
       if(!className) return;
       var reg = new RegExp(`\\b${className}\\b`, 'g');
       node.className = node.className.replace(reg, '').replace(/\s$/, '');
    }
    

    下面这种方法比较简单明了,且不会出错

    function removeClass(node, className){
        let tmpClassName = ' ' + className + ' ';
        if(node.className.indexOf(tmpClassName) >= 0){
            node.className = tmpClassName.replace(' ' + className + ' ', ' ');
        }
    }
    
    3、getCurrentStyleByNode获取节点的样式
        function getStyle:function(node,attr){
            return node.currentStyle ? node.currentStyle[attr] : getComputedStyle(node,0)[attr];
        }
    

    封装JS的DOM操作库

    var DOMUtil = {
        addClassName: function(){},
        removeClassName: function(){},
        getCurrentStyleByNode: function(){}
    }
    

    三、数组相关方法重写

    1、indexOf方法
    Array.prototype.indexOf = function (srcElement, fromIndex) {
        let index = -1;
        fromIndex = fromIndex || 0;
        for (let i = 0; i < this.length; i++) {
            curr = this[i]
            if (i >= fromIndex && srcElement === curr) {
                index = i;
                break;
            }
        }
        return index;
    }
    [0, 1, 2, 3].indexOf(3, 2)
    

    四、Number相关方法重写

    Number.prototype.toFixed = function(len){
         let times = Math.pow(10, len);
         return Math.round(this * times) / times;
    }
    

    相关文章

      网友评论

          本文标题:手写代码系列(持续更新)

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