手写new insfanceof promise 节流 防抖 深拷贝 快排

各种手写

###手写new

######new操作符做了什么事情:
1.创建一个空对象 将来会返回这个对象
2.调用构造函数,并将构造函数的this指向新创建的对象newObj
3.把原型对象的方法给新创建的newObj,把newObj的__proto__指向构造函数的显式原型
4.判断构造函数的返回值,来决定new的返回值是(构造函数的返回值还是实例化对象)

<script>
        //封装一个手写_new函数,当把构造函数传进去,就会模拟new 把它给实例化了
        function _new (obj, ...rest){
            // 创建一个新的对象并将这个对象的this指向obj的显示原型
            const newObj = Object.create(obj.prototype);
            // 将obj的this指向新创建的newObj对象并调用obj;并返回一个新的对象result;这个对象的参数为(rest)
            const result = obj.apply(newObj,rest)
            // 判断返回值:如果构造函数的返回值是一个对象则就返回这个对象,反之则返回这个新的对象(newObj)
            return typeof result === 'object' ? result : newObj
        }
        //摸拟一下
        // 声明一个构造函数
        function fn(name,age){
            this.name=name;
            this.age=age
            // 如果构造函数的返回值是对象则实例化之后就是这个对象
           /* return my= {
                data:'太难啦'
            }*/
        }
        fn.prototype.sry=function(){
            // 原型对象的this指向实列化对象
            console.log(this.name)
        }
        // new实例化调用
        const day1 = new fn('lily',22)
        const day2 = _new(fn,'laowang',29)
        console.log(day1)
        console.log(day2)
        // 通过实力化调用
        day1.sry()
        day2.sry()
    </script>

手写insfanceof

理解instanceof:

​ A instanceof B: B 的原型对象(prototype)是否在A的原型链(proto)上;B是构造函数 A是实例对像

 //声明一个函数将来调用这个函数的传入(A,B)就会返回true或者false 
//true代表在原型链上   false代表不在
function instanceOf(A, B) {
            //首先获取B的原型对象 然后再判断
            var BPrototype = B.prototype;
            while (A.__proto__) {
                if (A.__proto__ === BPrototype) {
                    return true;
                }
                A = A.__proto__;
            }
            return false;
        }

###手写promise

######promise的状态和值

​ 1.promise不是异步代码,而是盛放异步代码的工具,promise是一个构造函数,需要实例化调用

​ 2.Promise的两个参数是两个函数,resolve是成功函数,reject是失败函数,

​ 3.当执行完成后,如果成功则调用执行resolve函数,如果失败则调用执行reject函数,这样Promise的返回值就会接到通知

​ 4.如果Promise失败则返回的promise的状态就是rejected,如果Promise成功则返回的promise状态就是fulfilled/resolved

​ 5.如果Promise正在执行,或者你没有调用成功失败函数,那么promise的状态将一直都是pending

then方法的返回值

1.then返回值是一个新的promise1对象, 他的状态看里面函数调用的返回值:

​ 2.如果返回值是一个promise2对象,那么这个promise2的状态是什么,promise1的状态就是什么

​ 3.如果返回值不是promise对象,或者没有返回值,那么promise1对象默认是成功状态

​ 4.如果函数调用报错了,那么promise1对象就会是失败状态

######catch的返回值

​ 1.本质就是借用then的第二个失败的回调函数,所以catch的返回值也是和then的返回值规则一致

  function Mypromise(auto) {
        // 这里得this指向Myprpmise的实列对象,所以要保存起来 
        const that = this
        // 定义实列对象的默认状态为pending
        that._status = 'pending'
        // 定义实列对象的默认值为undefined
        that._result = undefined
        // 用来存储成功、失败回调函数的容器
        that._vessel = {}
        // 成功的函数resolve
        function resolve(value) {
            // 判断只能修改一次状态
            if (that._status !== 'pending') return
            //实列对象的状态和值
            that._status = 'resolved'
            that._result = value
            // 异步调用that._vessel.onResolved函数,因为同步的话that._vessel容器里面还没用onResolved这个回调函数,
            // 所以需要等待Mypromise调用成功函数resolve来触发显示原型上的then方法,then方法内会向that._vessel容器添加添加onResolved方法,
            // 简而言之需要等待that._vessel容器内有onResolved方法
            setTimeout(() => {
                // 容器内有这个方法并且调用他
                // that._vessel.onResolved && that._vessel.onResolved(value)
                that._vessel.onResolved?.(value)
            }, 0);
        }
        // 失败的函数reject
        function reject(failure) {
            if (that._status !== 'pending') return
            that._status = 'reject'
            that._result = failure
            setTimeout(() => {
                that._vessel.onRejected?.(failure)
            }, 0);
        }
        // 下面的代表:
        // 比如var p=new promise(function(resolve, reject){})
        // 这个function(resolve, reject)就相当于auto(resolve, reject)
        auto(resolve, reject)
    }
    // 在Mypromise的显示原型上添加then方法,该方法接收两个函数 onResolved, onRejected
    Mypromise.prototype.then = function (onResolved, onRejected) {
        // 原型上的this指向实例对象,先保存起来
        const that = this;
        /*由于catch 方法本质上是then方法的第二个回调函数,我们使用then的时候一般只写一个成功的回调函数,第二个回调函数由于不			写,所以下面就是解决不传then方法的第二个失败的的回调函数  */
        onRejected = typeof onRejected  === 'function' ? onRejected : (failure)=>{throw failure}
        // // 由于catch 方法本质上是then方法的第二个回调函数,第一传递是unedfined 所以下面解决的是catch方法不传第一个参数
        onResolved = typeof onResolved  === 'function' ? onResolved : value =>value
        // then方法返回的是一个新的promise对象,以此才能满足then方法的链式调用
        //    function(resolve, reject)这个就是构造函数Mypromise接收的参数
        return new Mypromise(function (resolve, reject) {
 		/*下面是then方法的第一个回调函数:如果第一个回调函数中返回的是promise对象则then方法的第一个回调函数的成功与否就取决于这个promise对象*/
            that._vessel.onResolved = function (value) {
                try {
                 // 获取onResolved方法的返回值来判断是不是promise的实例化对象
                    const result = onResolved(value)
                // 如果result是Mypromise的实例化对象则then的第一个回调函数的成功与否就看这个Mypromise实例化对象的状态
                    if (result instanceof Mypromise) {
               //result就是Mypromise的实例化对象,实例化对象就会then方法,result调用then方法来返回当前的Mypromise的状态
                        result.then(resolve, reject)
                    } else {
                        // 如果then中的第一个回调函数的返回值不是prommise对象则默认成功
                        resolve(result)
                    }
                } catch (e) {
                    // 如果then的第一个回调函数中出现错误啦则第一个回调函数的状态就失败
                    reject(e)
                }
            }
            // 下面是then方法的第二个回调函数原理和第一个回调函数一样:
            // 如果第二个回调函数中返回的是promise对象则then方法的第二个回调函数的成功与否就取决于这个promise对象
            that._vessel.onRejected = function (failure) {
                try {
                    const result = onRejected(failure)
                    if (result instanceof Mypromise) {
                        result.then(resolve, reject)
                    } else {
                        resolve(result)
                    }
                } catch (e) {
                    reject(e)
                }
            }
        })
    }
    // 在Mypromise的显示原型上添加catch方法,该方法接收一个函数  onRejected:catch方法只考虑失败
    Mypromise.prototype.catch = function (onRejected) {
     //this指向实例化对象.实例化对象中肯定有then方法,借用then方法的第二个回调函数就可以啦
        return this.then(undefined, onRejected);
    }

节流

概念:给某个元素绑定啦事件的时候,比如进入某个元素中 点击 移动等 ,这个时候只要鼠标移动点击,绑定的事件会不断的被触发,这是非常耗费性能的,所以要给元素绑定的事件做限制,只能在规定的事件内触发一次事件(第一次),到啦规定的时间才会在触发一次
function move(e) {
        console.log(Date.now());
        console.log(this); //应该是指向oBox
        console.log(e); //
      }
      const result = throttle(move, 5000);
      //当box事件触发的时候 会走看门狗
      oBox.onmousemove = result;
      //高阶函数
      //封装一个节流函数,参数:需要节流的功能函数  是每次功能函数调用所间隔的时间
      function throttle(fn, time) {
        //进来以后判断最新的时间和上一次访问的时间 间隔是否有200ms
        //如果有 则执行move函数  否则直接return
        //第一次进来没有上一次的时间,并且第一次一定是要执行的
        //所以直接给第一个进来设置一个上一次的默认时间是0
        let lastTime = 0;
        return function () {
          //获取当前进入的时间
          let nowTime = Date.now();
            //当前时间减去上一次时间要小于规定的时间的化就return
          if (nowTime - lastTime < time) {
            return;
          }
          //如果时间超出 则直接调用fn
          //当前return的函数this指向是box 所以需要把fn的this指向当前的this
          //当前的return的才是真正的事件函数,所以当前return的函数拥有event,但是fn没有
          //需要把当前return的函数的参数 给到fn上, 要把事件对象给到 arguments[0] 上, 然后功能函数才会有event事件对象
          fn.call(this, arguments[0]);

          //把lastTime更新一下 方便下次判断
          lastTime = nowTime;
        };
      }

防抖

概念:给某个元素绑定移动事件时,只要鼠标移动就不断触发,我们想要的是鼠标移动的最后一次才触发事件

 function move(e) {
        console.log(Date.now());
        console.log(this); //应该是指向oBox
        console.log(e); //
      }

      const result = debounce(move, 200);

      //当我最后一次移动完成之后 200毫秒后再执行
      oBox.onmousemove = result;

      function debounce(fn, time) {
        let timerID = null;
        return function () {
          //每次move一执行 就要重新触发 重新计时 所以需要清除计时器
          clearTimeout(timerID);
          const arg = arguments;
          //重新设置时间
          timerID = setTimeout(() => {
            //   将事件对象给arg[0] 功能函数才会有event事件对象
            fn.call(this, arg[0]);
          }, time);
        };
      }

深拷贝

概念:复制对象中的对象

const obj = {
  name: "xiaowang",
  age: 18,
  hobby: {
    one: "喝酒",
    two: "写代码",
  },
  score: [100, 90, 80],
  do() {
    console.log("eat");
  },
}

// 封装一个检测数据类型的方法
function checkType(obj) {
    return Object.prototype.toString.call(obj).slice(8, -1);
}
function deepClone(obj) {
    let re;
    //判断当前传进来的是对象的话则 re 就和传来的一样也是对象
    if (checkType(obj) === "Object") {
        re = {}
        //如果是数组则 re 也是数组
    } else if (checkType(obj) === "Array") {
        re = [];
    } else {
        //如果都不是就return出去
        return obj
    }
	//赋值给re 
    for (let i in obj) {
        
        re[i] = deepClone(obj[i])
    }
    return re;
}
//测试
const newObj = deepClone(obj);
newObj.name = "zhang";
console.log(obj.name);  //xiaowang
console.log(newObj.name);//zhang  说明拷贝的新的对象和旧的对象不是一个地址

快排

概念:数组快速小到大排序

 function quickSort(arr) {
            //确保数组的长度大于1
            if (arr.length <= 1) {
                return arr;
            }
            //根据数组的长度得出数字
            const num = Math.floor(arr.length / 2);
            //把原数组中的基准值删除掉,arr直接变成一个去除基准值的新数组,并且返回了一个删除元素的数组
            const Value = arr.splice(num, 1)[0];
            const left = [],
                right = [];
			//遍历原数组
            arr.forEach((item, index) => {
                if (item < Value) {
                    left.push(item);
                } else {
                    right.push(item);
                }
            })
            //递归并合并 ,concat方法将一维数字打散,将里面的值添加到数组尾部
            return quickSort(left).concat(Value, quickSort(right))
        }
		//测试
        const re = quickSort([1, 3, 5, 2, 11, 6, 4, 9, 7, 0]);
        console.log(re);//[0, 1, 2, 3, 4, 5, 6, 7, 9, 11]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值