面试题---手写系列

手写防抖

手写节流

手写科里化函数

简单版本的bind方法的实现

new方法的实现

实现instaceof方法

实现一个深拷贝方法

排平数组

饮料换购问题

封装判断两个对象相等的方法

手写防抖debounce

在事件被触发一定时间后再执行,如果在这段时间内再次触发,重新计时。如果一直触发,一直都不执行。

function debounce(fn,delay){
    let timer
    return function(){
        let context = this
        let args = arguments
        //如果已存在计时器 清空 重新计时
        timer && clearTimeout(timer)
        timer = setTimeout(function(){
            fn.apply(context,args)
        },delay)
    }
}

手写节流throttle

规定一段时间内,多次触发事件只能有一次触发执行。只有当此次触发执行完成后,下一次触发才能执行。会稀释执行次数。

function throttle(fn,delay){
    let timer
    return function(){
        let context = this
        let args = arguments
        //计时器不存在的情况下 才会执行 执行完会将timer清空
        if(!timer){
            timer = setTimeout(function(){
                timer = null
                fn.apply(context,args)
            },delay)
        }
    }
}

测试:

<div class="container" id="box"></div>
.container{
     width:100px;
     height:100px;
     background-color: blue;
 }
var box = document.getElementById("box")
box.addEventListener("click",debounce(function(){
    console.log("点击事件发生")
},2000))
box.addEventListener("click",throttle(function(){
    console.log("点击事件发生")
},2000))

手写科里化函数

function curry(fn,args){
    let length = fn.length
    args = args || []
    return function(){
        let finalArgs = args.concat(Array.from(arguments))
        //如果参数个数小于fn所需参数个数 返回函数
        if(finalArgs.length < length){
            return curry.call(this,fn,finalArgs)
        }else{
            return fn.apply(this,finalArgs)
        }
    }
}

测试:

function multi(a,b,c){
   return a+b+c
 }
 var fn = curry(multi,[1,2,3])
 console.log(fn()) //6
 var fn1 = curry(multi)
 console.log(fn1(1)(2)(3)) //6
 console.log(fn1(1,2,3)) //6
 var fn2 = curry(multi,[1,2])
 cosnole.log(fn2(3)) //6
 console.log(fn2(4)) //7 参数复用

简单版本的bind方法的实现

/*bind方法的实现*/
 Function.prototype.bindFn = function(thisArg){
     if(typeof this !== "function"){
         throw new TypeError(this+"must be a function")
     }
     //存储函数本身
     var self = this
     //存储除去thisArg之外的参数转成数组
     var args = Array.prototype.slice.call(arguments,1)
     var bound = function(){
         var finalArgs = args.concat(Array.prototype.slice.call(arguments))
         return self.apply(thisArg,finalArgs)
     }
     return bound
 }

测试:

var obj = {
     name:"Audrey"
 }
 function original(a,b){
     console.log(this.name)
     console.log([a,b])
 }
 var bound = original.bindFn(obj,1)
 bound(2)  //Audrey [1,2]

new方法的实现

/*new方法实现*/
function myNew(){
    //获取构造函数
    var constr = Array.prototype.shift.call(arguments)
    //创建一个新对象 新对象的原型指向构造函数的原型
    var obj = Object.create(constr.prototype)
    //执行构造函数
    var result = constr.apply(obj,arguments)
    //判断构造函数的执行结果 如果是对象 返回 否则返回新对象
    return result instanceof Object ? result : obj
}

测试:

function Person( name , age ){
   this.name = name
   this.age = age
   this.sayHi = function(){
       console.log(`hello,my name is ${this.name},I am ${this.age} years old`)
   }
}
var p1 = myNew(Person,'ls',18)
p1.sayHi() // hello,my name is ls,I am 18 years old

实现instaceof方法

function myInstance(left,right){
    while(true){
        if(left.__proto__ === right.prototype) return true
        if(left.__proto__ === null) return false
        left = left.__proto__
    }
}

测试:

function Person(name,age){
    this.name = name
    this.age = age
    this.sayHi = function(){
        console.log(`hello,my name is ${this.name}`)
    }
}
var p1 = new Person("zs",28)
console.log(myInstance(p1,Person)) //true
console.log(myInstance(p1,Object)) //true

实现一个深拷贝方法

function deepClone(source){
	//先判断要拷贝的是数组还是对象
    var target = Array.isArray(source) ? []:{}
    for(let key in source){
        if(source[key] instanceof Object){
        	//递归调用
            target[key] = deepClone(source[key])
        }else{
            target[key] = source[key]
        }
    }
    return target
}

测试:

var testO  = {
     a:"111",
     b:[1,2,"3"],
     c:{
         d:1,
         e:2
     }
 }
 var deepTestO = deepClone(testO)
 deepTestO.b[2] = "666"
 deepTestO.c.e=3
 console.log(deepTestO)
 console.log(testO)

排平数组

// 拍平数组
function flat(){
    let flattenArray = []
    return function faltten(array){
        for(let i=0;i<array.length;i++){
            Array.isArray(array[i])?faltten(array[i]):flattenArray.push(array[i])
        }
        return flattenArray
    }
}

测试:

var a = [1,[2],[[3,4]]]
var a1 = flat()
console.log(a1(a)) // [1,2,3,4]

饮料换购问题

一瓶饮料n元钱,k个瓶盖可以换一瓶饮料,问m元钱可以喝到多少瓶饮料?

function getBottles( m, n, k){
	//第一次可以买到的瓶数
	let initBottles = Math.floor( m / n)
	//总瓶数
	let sumCount = initBottles
	//第一次的剩余瓶盖数是0
	let initRestCaps = 0
	//每一轮 瓶子数 和 剩余瓶盖数
	function cycle( bottles , restCaps ){
		if( ( bottles + restCaps ) >= k ) {
			let currentBottles = Math.floor((bottles + restCaps) / k)
			let currentCaps = (bottles + restCaps) % k
			sumCount += currentBottles
			cycle( currentBottles,currentCaps )
		}
	}
	cycle(initBottles,initRestCaps)
	return sumCount
}

测试:

getBottles(10,3,2) // 5  10元 3元/瓶 2个瓶盖换一瓶
getBottles(20,1,2) //39  20元 1元/瓶 2个瓶盖换一瓶

封装判断两个对象相等的方法

function isDeepEqual(o1, o2) {
  let o1keys = Object.keys(o1);
  let o2keys = Object.keys(o2);
  let flag = true; //默认二者是相等的
  //如果二者的key数组长度不等 一定不相同
  if (o1keys.length !== o2keys.length) return flag = false;
  //如果二者的key数组长度相同
  for (let key in o1) {
    //判断o2是否有这个key
    if (o2[key]) {
      //如果是对象类型
      if (o1[key] instanceof Object && o2[key] instanceof Object) {
        flag = isDeepEqual(o1[key], o2[key]);
        if (!flag) {
          break;
        }
      } else {
        if (o1[key] !== o2[key]) {
          flag = false;
          break;
        }
      }
    } else {
      //如果o2中没有这个key 一定不相同 结束循环
      flag = false;
      break;
    }
  }
  return flag;
}

测试:

let a1 = {
 a: "11",
  b: {
    c: "1",
  },
};
let a2 = {
  b: "22",
  d: {
    e: "1",
  },
};
let c1 = { name: "audrey", age: 25, todo: [1, 2, 3] };
let c2 = { todo: [1, 2, 3], name: "audrey", age: 25 };
console.log(isDeepEqual(a1, a2)); //false
console.log(isDeepEqual(c1, c2)); //true
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值