首页 > 技术文章 > 2020面试系列-js手写代码

liuxiaoru 2020-09-06 19:17 原文

函数节流,防抖

 节流

//函数节流
function throttle(handler, wait) {
        let preTime = 0;
        return function () {
          let now = Date.now();
          if (now - preTime >= wait) {
            handler();
            preTime = now;
          }
        };
      }
      var t = throttle(function () {
        console.log(11);
      }, 1000);
      var oBtn1 = document.getElementById('btn1');
      oBtn1.onclick = function(){
          t();
      }

 防抖

//函数防抖
function debounce(handler, wait) {
        let timer = null;
        return function () {
          if(timer){
              clearTimeout(timer);
          }
          timer = setTimeout(
              handler,1000
          )
        };
      }

      var t = debounce(function () {
        console.log(11);
      }, 1000);

      document.onmousemove = function(){
          t();
      }

  

 

实现call,apply,bind

call

Function.prototype.mcall = function (context) {
  //传参第一个参数转对象,不传参直接去window
  let ctx = Object(context) || window;
  let fn = "fn",
    res = "";
  while (ctx.hasOwnProperty(fn)) {
    // 循环判断并重新赋值 ,防止上下文对象上本来就有同名方法
    fn = fn + Math.random();
  }
  //把绑定函数作为上下文对象的方法
  ctx[fn] = this;
  //作为对象方法调用绑定函数,并把参数传入
  if (arguments.length > 1) {
    res = ctx[fn](...[...arguments].slice(1));
  } else {
    res = ctx[fn]();
  }
  delete ctx[fn];
  //返回函数返回值
  return res;
};

apply

Function.prototype.mapply = function (context, arr) {
  let ctx = Object(context) || window;

  let fn = "fn",
    res = "";
  while (ctx.hasOwnProperty(fn)) {
    fn = fn + Math.random();
  }

  ctx[fn] = this;

  if (arr) {
    res = ctx[fn](...arr);
  } else {
    res = ctx[fn]();
  }

  delete ctx[fn];
  return res;
};

bind

Function.prototype.mbind = function (context) {
  context = context ? Object(context) : window;
  //保存argumets
  var mArguments = arguments,
    self = this;
  if (arguments.length > 1) {
    return function () {
      //借用apply
      self.apply(context, [...mArguments].slice(1));
    };
  } else {
    return function () {
      self.apply(context);
    };
  }
};

  

实现数组实例方法

push

//push 从后面新增
Array.prototype.push = functon(){
  for(var i =0;i<arguments.length;i++){
    this[this.length-1] = arguments[i];
  }
  return this.length;
}  

POP

//pop 从后面删除一个
Array.prototype.pop = function(){
  var item = this[this.length-1];
  if(this.length>0){
    this.length = this.length - 1;
  }
  return item;

}

 shift

//shift 从前面删除一项
Array.prototype.shift = function(){
  var item = this[0];
  for(var i = 1;i<this.length;i++){
    this[i-1] = this[i];
  }
  this.length = this.length-1;
  return item;
}

unshrft

//unshift 从前面增加n项
Array.ptototype.unshift = function(){
  var l = arguments.length;
  //把原数组向后移动
  for(var i= 0;i<this.length;i++){
    this[i+l] = this[i];
  }
  //赋值
  for(var j = 0;j<arguments.length;j++{
    this[j] = arguments[j];
  }
  return this.length;
}

 filter

//fitler
Array.prototype.fitler = function(handler){
  var newArr = [];
 for(var i = 0;i<this.length;i++){
   if(handler(this[i],i,this)){
    newArr[newArr.length] = this[i];
   }
 }
  return newArr;
}

  

数组去重

//普通去重
function unique(arr) {
  var newArr = [];
  arr.forEach((item, index, arr) => {
    if (newArr[newArr.length] != item) {
      newArr[newArr.length] = item;
    }
  });
  return newArr;
}
//indexOf去重
function unique(arr) {
  var newArr = [];
  arr.forEach((item, inddex, arr) => {
    if (newArr.indexOf(item) == -1) {
      newArr.length = item;
    }
  });
  return newArr;
}
//利用对象属性不能相同
function unique(arr) {
  var obj = {},
    newArr = [];
  arr.forEach((item, index, arr) => {
    if (!obj[item]) {
      obj[arr[i]] = 1;
      newArr.push(item);
    }
  });
  return newArr;
}
//es6去重
function unique(arr) {
  return Array.from(new Set(arr));
}
//扩展运算符
function unique(arr) {
  return [...new Set(arr)];
}

  

排序算法

//冒泡排序
//相邻两元素之间两两比较,比较出大值进行赋值互换,再依次与相邻的元素比较,层层递进
//假设升序排序
function bubbleSort(arr) {
  var l = arr.length;
  for (var i = 0; i < l; i++) {
    //比较轮数
    for (var j = 0; j < l - i - 1; j++) {
      //每一轮确定一个最大值,放最右边
      var temp = arr[j];
      if (arr[j] > arr[j + 1]) {
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
  return arr;
}

//选择排序
//先假设一个值为最大或者最小值

function selectSort(arr){
  for(var i = 0;i<arr.length;i++){
    var minIndex = i; 
    for(var j = i;j<arr.length;j++){
      if(arr[j]>arr[j+1]){
        minIndex=j+1;
        var temp = arr[j];
        arr[j] = arr[j+1];
        arr[j+1] = temp;
      }
    }
  }

}
//快速排序
//找基准,遍历数组,小于基准的放在left,大于基准的放在right,最后递归
function quickSAort(arr){
  if(arr.length<=1>)return arr;
  var temp = arr[0],left=[],right =[];
  for(var i = 1;i<arr.length;i++){
    if(arr[i]<temp){
      left.push(arr[i])
    }else{
      right.push(arr[i])
    }
  }
  return [].concat(quickSort(left),temp,quickSort(right));
}

  

深拷贝

//深拷贝黑科技
JSON.parse(JSON.stringify(obj));
//存在问题:无法拷贝原型上的属性和方法

//递归实现
function deepCopy(obj) {
  var newobj = obj.constructor === Array ? [] : {};
  if (typeof obj !== "object") {
    return obj;
  } else {
    for (var i in obj) {
      //判断对象的这条属性是否为对象,//若是对象进行嵌套调用,否则直接赋值
      newobj[i] = typeof obj[i] === "object" ? deepCopy(obj[i]) : obj[i];
    }
  }
  return newobj; //返回深度克隆后的对象
}

  

拉平多维数组

//简便方法
function flatArr(arr) {
  return arr.join(",").split(",");
}
//递归实现
function flat(arr) {
  let arr1 = [];
  arr.forEach((val) => {
    if (val instanceof Array) {
      arr1 = arr1.concat(flat(val));
    } else {
      arr1.push(val);
    }
  });
  return arr1;
}

  

setTimeout模拟定时器

function mInterval() {
  //要执行的逻辑
  console.log(1);
  //每次逻辑执行完,才会向队列添加事件
  setTimeout(mInterval, 1000);
}

mInterval();

  

手写promise

promise

//判断变量是否是函数
function isFunction(variable) {
  return typeof variable === "function";
}

//promise构造函数
function MyPromise(handle) {
  if (!isFunction(handle)) {
    throw new Error("必须传入一个函数");
  }
  this.status = "pending"; //状态,默认等待状态
  this.value = ""; //值
  this.onResolveCallbacks = []; //存放成功回调的数组
  this.onRejectCallbacks = []; //存放失败回调的数组
  var that = this;
  try {
    handle(resolve, reject);
  } catch (err) {
    reject(err); //有报错,状态直接变为rejected
  }

  function resolve(val) {
    if (that.status == "pending") {
      that.status = "resolved";
      that.value = val;
      that.onResolveCallbacks.forEach((fn) => {
        fn();
      });
    }
  }

  function reject(err) {
    if (that.status == "pending") {
      that.status = "rejected";
      that.value = err;
      that.onRejectCallbacks.forEach((fn) => {
        fn();
      });
    }
  }
}

 

promise.then

MyPromise.prototype.then = function (sucFun, faildFun) {
  //可选参数
  //如果没有传,只负责把值往后传
  sucFun = isFunction(sucFun) ? sucFun : (value) => value;
  faildFun = isFunction(faildFun) ? faildFun : (value) => value;
  var that = this;
  //先改变了状态
  if (this.status === "resolved") {
    sucFun(this.value);
  }
  if (this.status === "rejected") {
    faildFun(this.value);
  }
  //先指定了回调函数,状态还没改变
  if (this.status === "pending") {
    //存住回调函数,在异步操作完成时调用
    this.onResolveCallbacks.push(() => {
      sucFun(this.value);
    });
    this.onRejectCallbacks.push(() => {
      faildFun(this.value);
    });
  }

  return this;
};

 promise.all

Promise.allFun = (arr) => {
  return new Promise((resolve, reject) => {
    var resolveArr = [],
      rejectArr = [];
    for (var i = 0; i < arr.length; i++) {
      if (!(arr[i] instanceof Promise)) {
        arr[i] = Promise.resolve(arr[i]);
      }
      arr[i]
        .then((res) => {
          resolveArr.push(res);
          if (resolveArr.length == arr.length) {
            resolve(resolveArr);
          }
        })
        .catch((err) => {
          rejectArr.push(err);
          reject(rejectArr);
        });
    }
  });
};

promise.race

myPromise.race = function (arr) {
  return new Promise(function (resolve, reject) {
    for (var i in arr) {
      arr[i].then(resolve, reject);
    }
  });
};

  

实现一个并发请求控制方法

async function sendRequest(list, max = 4) {
  return new Promise((resolve, reject) => {
    let index = 0; //
    let count = 0; //上传成功个数
    const start = () => {
      while (max > 0 && index < list.length) {
        //剩余位置-1
        max--;
        let chunk = list[index];
        index++;
        request().then((res) => {
          max++; //释放暂用位置
          count++; //上传成功数量+1
          if (count == list.length) {
            resolve("完成了");
          } else {
            start();
          }
        });
      }
    };

    start();
  });
}

function request() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(1);
      resolve(1);
    }, 2000);
  });
}

var list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1];
sendRequest(list, 4)
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.log("上传失败了");
  });

  

实现new

function new() {
  //创建空对象
  let obj = {};
  //获取构造函数
  let Constructor = Array.prototype.shift.call(arguments);
  //绑定原型关系
  obj.__proto__ = Constructor.prototype;
  // 执行构造函数,即绑定 this,并且为这个新对象添加属性
  Constructor.apply(newObj, arguments);
  //返回新对象
  return obj;
}

  

Object.create

新创建一个对象,使用传入对象作为新对象的原型对象

Object.create = function (obj) {
  //创建空构造函数F
  function F() {}
  //F的prottotype指向obj
  F.prtotype = obj;
  //返回F实例
  return new F();
};

  

输出数据类型

function getType(param){
        if(param){
           return Object.prototype.toString.call(param).split(' ')[1].split(']')[0];
        }else{<br>       console.log('参数不能为空')<br>      }
 
     }

 斐波那契数列

//给定位置,输出对应的值
function fib(n){
        if(n==1||n==2){
            return 1;
        }
        return fib(n-1)+fib(n-2)
      }

  

推荐阅读