JS面试必备之手写instanceof,深拷贝,节流和防抖
作者:feelingHy
JavaScript如何实现手写instanceof、深拷贝、节流、防抖也是面试时常常考到的知识点,这篇文章为大家进行了详细介绍,需要的可以参考一下
一、instanceof 的实现
使用 instanceof 操作符,如果一个实例的原型链中出现过相应的构造函数的原型,则 instanceof 返回 true。
instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。 因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例。
function instanceof1(L,R) { L = L.__proto__; while(L != null) { if(L === R.prototype) { return true; } L = L.__proto__; } return false; }
二、浅拷贝
// 浅拷贝 function shallowClone(obj) { const result = {}; for(let key in obj) { console.log('ddddd',key); if(obj.hasOwnProperty(key)) { result[key] = obj[key]; } } return result; }
测试代码:
let obj = { b: { c: [1, 5, 11, 23, 422] }, d: function() { console.log('hello world'); } }; const result = shallowClone(obj); console.log(result); const newObj = Object.assign({},obj); console.log(newObj);
三、深拷贝
// 深拷贝 function deepClone(obj) { if(typeof obj != 'object' || obj == null) { return obj; } const result = Array.isArray(obj) ? [] : {}; for(let key in obj) { // 自有属性 if(obj.hasOwnProperty(key)) { const type = typeof obj[key]; if(type == 'object' && obj[key] != null) { result[key] = deepClone(obj[key]); } else { result[key] = obj[key]; } } } return result; }
测试代码:
var data = { age: 18, name: "liuruchao", education: ["小学", "初中", "高中", "大学", undefined, null], likesFood: new Set(["fish", "banana"]), friends: [ { name: "summer", sex: "woman"}, { name: "daWen", sex: "woman"}, { name: "yang", sex: "man" } ], work: { time: "2019", project: { name: "test",obtain: ["css", "html", "js"]} }, play: function() { console.log("玩滑板"); } } console.log(deepClone(data));
解决循环引用问题:
// 解决循环引用问题 function deepClone2(obj, hash = new WeakMap()) { const type = typeof obj; if(type != 'object' || obj == null) { return obj; } if(hash.has(obj)) { return hash.get(obj); } const result = Array.isArray(obj) ? [] : {}; for(let key in obj) { if(obj.hasOwnProperty(key)) { if(typeof obj[key] != 'object' || obj[key] == null) { result[key] = obj[key]; } else { // 首次调用时,weakMap为空,不会走上面那个if(hash.has())语句,如果待拷贝对象中有属性也为对象时, // 则将该待拷贝对象存入weakMap中,此时的健值和健名都是对该待拷贝对象的引用 hash.set(obj, obj) result[key] = deepClone2(obj[key], hash); } } } return result; }
测试代码:
var data2 = { name: 'foo', child: null, } data2.child = data2; console.log(deepClone2(data2));
四、函数防抖
- 当持续触发事件时,一定时间内没有再触发事件,事件处理函数才会执行一次;
- 如果在设定的时间来到之前,又一次触发了事件,则会取消上次事件,重新开始计时;
使用场景:resize、scroll、输入框内容校验等。
function debounce(handle,wait) { let timer = null; return function () { if(timer != null) { clearTimeout(timer); } timer = setTimeout(handle, wait); } }
五、节流
当持续触发事件时,保证一定时间内只调用一次事件处理函数。通俗解释就比如:我们把水龙头打开,水哗哗的往外流,秉着节约的原则,我们要把水龙头关小,最好是如我们的心愿按照一定的规律,在某个时间内一滴一滴的往下滴。
时间戳版本:
function throttle (handle,wait) { let prev = Date.now(); return function() { let current = Date.now(); if(current - prev >= wait) { handle(); prev = Date.now(); } } }
定时器版本:
- 当触发事件的时候,我们设置一个定时器;
- 当再次触发的时候,如果定时器存在,就不执行,直到 wait 时间后,定时器执行 handle 函数,并且清空定时器,这样就可以设置下一个定时器;
- 当第一次触发事件时,不会立即执行行数,而是在 delay 秒之后才执行,而后在怎么频繁触发也都是在 wait 时间才执行一次。
function throttle1(handle, wait) { let timer = null; return function() { if(!timer) { timer = setTimeout(() => { handle(); timer = null; },wait); } } }
定时器 + 时间戳版本:
- 节流中使用时间戳和定时器版本都是可以的,更精确的,可以使用时间戳和定时器相结合,当第一次事件触发时马上执行事件处理函数,最后一次触发时也还会执行一次事件处理函数。
- 在节流函数内部使用了 pre 和 current 与 wait 来计算剩余时间 remaining,当 remaining <= 0 时,表示执行该执行事件处理函数了(保证了第一次触发事件就能立即执行事件处理函数和每隔 wait 时间执行一次事件处理函数)。
- 如果还没到时间的话就设定在remaining时间后再触发 (保证了最后一次触发事件后还能再执行一次事件处理函数)。当然在 remaining 这段时间中如果又一次触发事件,那么会取消当前的计时器,并重新计算一个remaining来判断当前状态。
function throttle2 (handle, wait) { let pre = Date.now(); let timer = null; return function() { let current = Date.now(); let remaining = wait - (current - pre); clearTimeout(timer); if(remaining <= 0) { handle(); pre = Date.now(); } else { timer = setTimeout(handle, remaining); } } }
节流和防抖总结:
- 函数防抖:将几次操作合并为一次操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay 时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
- 函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。
- 区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。
以上就是JS面试必备之手写instanceof,深拷贝,节流和防抖的详细内容,更多关于JS面试的资料请关注脚本之家其它相关文章!