手动实现new、深拷贝、防抖、节流等js原生方法

一、手动实现new操作符

new操作符的实现过程包括以下几个步骤:
1、创建一个空对象
2、将空对象的__proto__指向构造函数的 prototype
3、将空对象的this值绑定到构造函数上;
4、通过new创建的对象,其prototype最终将指向构造函数的prototype
5、如果函数没有显式返回对象类型,那么new会返回这个this
根据new操作符的作用原理,我们可以创建以下函数来实现new

function New(func){
	let res = {}
	if(func.prototype !== null){
		res.__proto__ = func.prototype
	}
	let ret = func.apply(res, Array.from(arguments))
	if(['function', 'object'].includes(typeof ret) && ret !== null){
		return ret
	}
	return res
}

二、手动实现一个深拷贝

在这里首先要针对对象,区分一下赋值浅拷贝深拷贝的区别。
赋值:当我们把对象赋值给一个变量的时候,赋的实际上是对象在栈中的地址,而不是在堆中的数据。
浅拷贝:浅拷贝是按位拷贝对象,它会获得一个新对象。如果对象属性是基本数据类型,那么就会获得基本数据类型的属性;如果是引用类型,那么就会获得引用地址。浅拷贝获得的新旧对象,其第一层数据是不共享的。如果有嵌套数据,那么新旧对象会共享嵌套数据,修改新对象会影响原对象。
深拷贝:深拷贝也是获得一个全新的对象。和浅拷贝不同的是,深拷贝获取到的对象,每一层数据都获得一份拷贝,新旧数据完全相互独立,互不影响。
深拷贝方法
对于Json安全(也就是一个可以被序列化成Json字符串,并且可以根据这个字符串解析出结构和值完全一样的对象)的对象来说,可以采用以下方法:

let newObj = JSON.parse(JSON.stringify(obj))

对于其他对象,可以手写一个深拷贝方法:

//深拷贝方法
function deeClone(obj){
	let newObj 
	if(typeof obj === 'object' && obj !== null){ //如果是引用类型
		newObj = obj.constructor === Array? [] : {}
		for(i in obj){ //遍历对象属性的key值
			newObj[i] = typeof obj[i] === 'object' ? deeClone(obj[i]) : obj[i]
		}
	}else { //如果是基本数据类型
		newObj = obj
	}
	return newObj
}

三、手动实现instanceOf

instanceOf操作符常用来判断一个实例是否属于某种类型。

// 判断 foo 是否是 Foo 类的实例
 function Foo(){}
 var foo = new Foo();
 console.log(foo instanceof Foo)//true

实现instanceOf操作符,关键在于判断实例的__proto__是否与指定对象类型的prototype相同

//手动实现instanceof
function instanceOf(left, right){
	let proto = left.__proto__
	let prototype = right.prototype
	while(true){ //追溯到原型链顶端
		if(proto === null) return false
		if(proto === prototype) return true
		proto = proto.__proto__
	}
}

四、手动实现防抖函数

针对页面高频度触发事件问题,有两种常用的解决方法,防抖和节流。
防抖
当一次事件发生后,事件处理器要等一定阈值的时间,如果这段时间过去后 再也没有事件发生,就处理最后一次发生的事件。假设还差 0.01 秒就到达指定时间,这时又来了一个事件,那么之前的等待作废,需要重新再等待指定时间。

//手动实现防抖函数
function debounce(fn, wait, immedite){
	let timer;
	let debounced =  function(){
		let context = this
		if(timer){
			clearTimeout(timer)
		}
		if(immedite){ // 是否立即执行
			let callNow = !timer
			if(callNow){
				fn.apply(context,arguments)
			}
			timer = setTimeout(() => {
				timer = null //闭包引用了timer,手动置空使其能被垃圾回收机制回收
			}, wait);
		}else{
			timer = setTimeout(()=>{
				fn.apply(context,arguments)
			},wait)
		}
	}
	debounced.cancel = function(){ //取消立即执行
		clearTimeout(timer)
		timer = null
	}
	return debounced
}

五、手动实现节流函数

可以理解为事件在一个管道中传输,加上这个节流阀以后,事件的流速就会减慢。实际上这个函数的作用就是如此,它可以将一个函数的调用频率限制在一定阈值内,例如 1s,那么 1s 内这个函数一定不会被调用两次
节流:限制一个函数在一定时间内只能执行一次

//节流函数
function throttle(fn, wait){
    let prev = new Date() 
    return function(){
        let args = arguments
        let now = new Date()
        if(now - prev > wait){
            fn.applay(this, args)
            prev = new Date()
        }
    }
}

//操作函数
function handle(){
    console.log(Math.random())
}

//实现函数防抖⬇️,表示监听mouseover事件。在5秒内,mouseover事件只会被触发一次
window.addEventListener("mouseover", throttle(handle, 5000))

防抖:控制事件触发的次数;节流:控制事件触发的频率

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值