手动实现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))
上一篇: android 匹配so文件规则