前言
系列首发于公众号『前端进阶圈』 ,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。
面试必考: 手撕代码系列(一)
手写深拷贝 (deepClone)
/** * deepClone 深拷贝 * @param {*} source 源对象(须要拷贝的对象) * @returns 新对象 */const deepClone = source => { // 存储后果 const obj = {}; // for...in 办法:遍历对象时 key 为对象的键;遍历数组时 key 为数组下标 index for (const key in source) { // Object.prototype.hasOwnProperty.call(); 办法是一个罕用的,平安监测对象是否含有某个属性的办法,应用此办法可防止 hasOwnProperty 属性被净化或被重写的危险。 if (Object.prototype.hasOwnProperty.call(source, key)) { // Object.prototype.toString.call(); 通过原型的形式判断一个值的类型 // 为什么应用 xxx.slice(8, -1)? // 因为 Object.prototype.toString.call() 返回的值是 [object Object], 应用 slice 办法截取 if (Object.prototype.toString.call(source[key]).slice(8, -1) === 'Object') { // 递归 obj[key] = deepClone(source[key]); } else { // 赋值 obj[key] = source[key]; } } } return obj;};// test:const a = { age: 12, otherInfo: { sex: 0, },};const b = deepClone(a);b.age = 22;b.otherInfo.sex = 1;console.log('a------>', a); // a------> { age: 12, otherInfo: { sex: 0 } }console.log('b------>', b); // b------> { age: 22, otherInfo: { sex: 1 } }
手写浅拷贝 (shallowClone)
逻辑同深拷贝相似,浅拷只会影响一层数据结构
/** * shallowClone 浅拷贝 * @param {*} source 源对象(须要拷贝的对象) * @returns 新对象 */const shallowClone = source => {const obj = {};for (const key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { obj[key] = source[key]; }}return obj;};// test:const a = {age: 12,otherInfo: { sex: 0,},};const b = shallowClone(a);b.age = 22;b.otherInfo.sex = 1;console.log('a------>', a); // a------> { age: 12, otherInfo: { sex: 1 } }console.log('b------>', b); // b------> { age: 22, otherInfo: { sex: 1 } }
手写 new 操作符 (customNew)
/** * customNew new操作符 * @param {*} fn 一般函数(!不能是箭头函数) * @param {*} rest 参数 * @returns 新对象(相似于实例) */const customNew = (fn, ...rest) => { // 1.创立一个新对象 const obj = {}; // 2.让新对象的隐士原型等于函数的显示原型 obj.__proto__ = fn.prototype; // 3.绑定 this, 让函数的 this 指向这个新对象(也就是绑定一些属性) const res = fn.apply(obj, rest); // 4.判断返回 return Object.prototype.toString.call(res).slice(8, -1) === 'Object' ? res : obj;};// test:function Person(name, age) { this.name = name; this.age = age;}Person.prototype.getName = function () { return this.name;};const person = customNew(Person, 'John', 11);console.log('person ------->', person); // person -------> Person { name: 'John', age: 11 }console.log('person.getName() ------->', person.getName()); // person.getName() -------> John
手写节流 (throttle)
/** * throttle 节流 * 某一段时间内只触发一次,按第一次来算 * @param {*} fn 办法 * @param {*} time 工夫(默认 1500ms) * @returns */const throttle = (fn, time = 1500) => { // 标记状态 let flag = null; return function () { // 若 flag 为 true, 则继续执行,不做任何操作 if (flag) return; // 更改标记状态 flag = true; // 执行办法 fn(); // 定时器 let timer = setTimeout(() => { // time 完结,批改 flag = false flag = false; // 革除定时器标记 clearTimeout(timer); }, time); };};
手写防抖 (debounce)
/** * debounce 防抖 * 某一段时间内只触发一次,按最初一次来算 * @param {*} fn 办法 * @param {*} time 工夫(默认 1500ms) * @returns */const debounce = (fn, time = 1500) => { // 定期器标记 let timer = null; return function () { // 若 timer 为 true, 则进行之前办法,从新开始 timer && clearTimeout(timer); timer = setTimeout(() => { // 执行办法 fn(); }, time); }};
特殊字符形容:
- 问题标注
Q:(question)
- 答案标注
R:(result)
- 注意事项规范:
A:(attention matters)
- 详情形容标注:
D:(detail info)
- 总结标注:
S:(summary)
- 剖析标注:
Ana:(analysis)
提醒标注:
T:(tips)
往期举荐:
- 前端面试实录HTML篇
- 前端面试实录CSS篇
- JS 如何判断一个元素是否在可视区域内?
- Vue2、3 生命周期及作用?
- 排序算法:QuickSort
- 箭头函数与一般函数的区别?
- 这是你了解的CSS选择器权重吗?
- JS 中 call, apply, bind 概念、用法、区别及实现?
- 罕用位运算办法?
- Vue数据监听Object.definedProperty()办法的实现
- 为什么 0.1+ 0.2 != 0.3,如何让其相等?
- 聊聊对 this 的了解?
JavaScript 为什么要进行变量晋升,它导致了什么问题?
最初:
- 欢送关注 『前端进阶圈』 公众号 ,一起摸索学习前端技术......
- 公众号回复 加群 或 扫码, 即可退出前端交流学习群,一起高兴摸鱼和学习......
- 公众号回复 加好友,即可添加为好友