手撕

110 阅读2分钟

1. 数组去重

        function quChong(arr) {          
          return [...new Set(arr)]        
        }

        Array.from(new Set(array))

2. 数组扁平化

        function flat(arr) {
          let stack = [...arr]          
          let res = []          
          while(stack.length){
            const next = stack.pop()
            if(Array.isArray(next)) {
              stack.push(...next)            
            } else {
              res.unshift(next)            
            }          
          }          
          return res       
        }

3. 二分查找

        function twoSort(arr,target){
          let left = 0;          
          let right = arr.length - 1; 
          while(left<=right) {
            let mid = Math.floor((left + right) / 2)
            // let mid = (left + right) >> 1            
            if(arr[mid] == target) {
              return mid            
            } else if(arr[mid] < target) {
              left = mid + 1            
            } else {
              right = mid - 1            
            }          
          }          
          return -1;        
        }        
        console.log(twoSort([1,2,3,4,5],2))

4. 节流

      function thorrle(fn, delay) {
        let preTime = Date.now()        
        return function() {
          let that = this
          let args = arguments
          let nowTime = Date.now()
          if(preTime - nowTime >= delay) {
            preTime = Date.now();
            fn.apply(that,args)
          }
       }

5. 防抖

      function debounce(fn, delay) {
        let time = null
        return function() {
          // 绑在在dom上,否则绑定在window上
          let args = arguments
          let that = this
          if(time) {
            clearTimeout(time)
            time = null
          }
          timer = setTimeout(()=>{
            fn.apply(that,args)
          },delay)
        }
      }

6. promise封装ajx

      const getJson = function(url){
        return new Promise((resolve,reject)=>{
           let xhr = new XMLHttpRequest();
           xhr.open('GET',url)
           xhr.setRequestHeader("Content-Type",'application/json')
           xhr.onreadystatechange = function() {
             if(xhr.readyState !== 4) {
               return;
             }
             if(xhr.status === 200 || xhr.status === 304) {
               resolve(xhr.responseText)
             } else {
               reject(new Error(xhr.responseText))
             }
           };
           xhr.send()
        })

7. 手写instanceof

     // 构造函数的原型对象是否在原型链上,对返回true,否则false      
     function myInstanceof(left, right) {
       while(true) {
       if(left == null) {
         return false;          
       }           
       if(left.__proto__ === right.prototype){
         return true          
       }
       else { 
         left = left.__proto__;          
       }
      }  
     }

8. 手写promise.all和race

      function all(arr){
        let count = 0
        let result = []
        return new Promise((resolve,reject)=>{
          for(let i = 0;i < arr.length;i++ ){
            Promise.resolve(arr[i]).then(
              (res) => {
                result[i] = res
                count++
                if(count === arr.length) {
                  resolve(result)
                }
              },
              (err) => {
                reject(err)
              }
            )
          }
         })
      }

      function race(arr){
        return new Promise(function (resolve, reject) {
          promises.forEach(p =>
             Promise.resolve(p).then(data => {
                     resolve(data)
                   }, err => {
                     reject(err)
                 })
               )
            })
         }

9.洗牌

      function randomNumber(arr){
        let len = arr.length - 1
        let t
        for(let i = 0; i < len; i++) {
          let index = parseInt(Math.random() * (len + 1 - i))
          t = arr[index]
          arr[index] = arr[len - i]
          arr[len - i] = t;
        }
        return arr
      }

10. 深拷贝

// 深拷贝的实现
function deepCopy(object) {
  // 补全代码
  if(!(typeof target=='object'))
     return target
  let copyOne=Array.isArray(target)?[]:{}
  for(let key in target){
      let value=target[key]
      if(typeof value=='object'){
        copyOne[key]=_sampleDeepClone(value)
       }else{
        copyOne[key]=value
       }
    }
    return copyOne
   }

11. bind

  • 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。

  • 保存当前函数的引用,获取其余传入参数值。

  • 创建一个函数返回

  • 函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。

      Function.prototype.myBind=function(context){
        if(typeof this!="function"){
          throw new TypeError("Error")
        }
        let args = [...arguments].slice(1)
        let fn = this
        return function Fn(){
          return fn.apply(
            this instanceof Fn ? this:context,
            args.concat(...arguments)
          )
        }
      }
    

12.new

function myNew(fn, ...args) {
  let obj = Object.create(fn.prototype);
  let res = fn.call(obj, ...args);
  if (res && (typeof res === "object" || typeof res === "function")) {
    return res;
  }
  return obj;
}

13. 发布订阅模式

      // 发布订阅模式
      class EventEmitter {
        constructor() {
        // 事件对象,存放订阅的名字和事件
        this.events = {}
      }
      // 订阅事件的方法
      on(eventName, callback) {
        if (!this.events[eventName]) {
        // 注意是数据,一个名字可以订阅多个事件函数
        this.events[eventName] = [callback]
        } else {
          // 存在则push到指定数组的尾部保存
          this.events[eventName].push(callback)
        }
      }
      // 触发事件的方法
      emit(eventName) {
        // 遍历执行所有订阅的事件
        this.events[eventName] && this.events[eventName].forEach((cb) => cb())
      }
      // 移除订阅事件
      removeListener(eventName, callback) {
        if (this.events[eventName]) {
          this.events[eventName] = this.events[eventName].filter(
            (cb) => cb != callback
          )
        }
      }
       // 只执行一次订阅的事件,然后移除
      once(eventName, callback) {
        // 绑定的时fn, 执行的时候会触发fn函数
      let fn = () => {
        callback() // fn函数中调用原有的callback
        this.removeListener(eventName, fn) // 删除fn, 再次执行的时候之后执行一次
        }
        this.on(eventName, fn)
      }
    }

14. 12345

      for(let i=1;i<=5;i++){
        setTimeout(function(){
          console.log(i)
        },i*1000)
      }

      for(var i=1;i<=5;i++){
        (function(i){
          setTimeout(function(){
            console.log(i)
          },i*1000)
        })(i)
      }

15.  组合继承

原型式继承:利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型。

      function father(name,age) {
        this.name = age
      }
       function son(){
        // 不能继承方法
        father.call(this,"big",22)
      }
      let erzi = new son();
      son.prototype = new father()
      // son的构造函数指向了父类
      son.prototype.constructor = son
      console.log(erzi.name);

原型式继承:利用一个空对象作为中介,将某个对象直接赋值给空对象构造函数的原型。
 function object(obj){
  function F(){}
  F.prototype = obj;
  return new F();
}

16.  jsonp

      function Jsonp(url){
        let script = document.createElement('script')
        script.src = url
        script.type = "text/javascript"
        document.body.appendChild(script)
      }
      Jsonp("http:www.123.com?callback=handres")
      function handres(res){
        console.log(res)
      }
      handres({a:1,b:2})

17.settimeout实现setinterval

     function mySetInterval(fn,time){
        let timer = null
        function interval() {
          fn();
          timer =setTimeout(interval,time);
        }
        interval()
      }

      function mySetTimeOut(fn,time){ 
       let time = null
       let timer = setInterval(() => {
          clearInterval(timer)
          fn()
        }, 
       time);
      }

18.科利华

        var args = [...arguments];
        console.log(args);
        var fn=function(){
          args.push(...arguments);
          return fn
        };
        fn.toString=function(){
          return _args.reduce(function (a, b) {
            return a + b;
          });
        };
        return fn
      } 

19.apply

Function.prototype.myApply = function(context) {
  // 判断调用对象是否为函数
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  let result = null;
  // 判断 context 是否存在,如果未传入则为 window
  context = context || window;
  // 将函数设为对象的方法
  context.fn = this;
  // 调用方法
  if (arguments[1]) {
    result = context.fn(...arguments[1]);
  } else {
    result = context.fn();
  }
  // 将属性删除
  delete context.fn;
  return result;
};

20.call

// call函数实现
Function.prototype.myCall = function(context) {
  // 判断调用对象
  if (typeof this !== "function") {
    console.error("type error");
  }
  // 获取参数 处理传入的参数,截取第一个参数后的所有参数。  let args = [...arguments].slice(1),
      result = null;
  // 判断 context 是否传入,如果未传入则设置为 window
  context = context || window;
  // 将调用函数设为对象的方法
  context.fn = this;
  // 调用函数
  result = context.fn(...args);
  // 将属性删除
  delete context.fn;
  return result;
};