步骤口述参考,实现笔试参考
防抖,节流,拷贝更丰富实现参考lodash
实现debounce
防抖,间隔时间内多次触发,只执行一次(输入校验)
步骤
- 设置定时器,如果时间没有到触发,重置定时器
- 返回高阶函数,闭包共享定时器变量
实现
function debounce(fn, delay) {
let timer = null;
return function() {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, arguments), delay)
}
}
实现throttle
节流,间隔时间内多次触发,间隔时间只执行一次(scroll)
步骤
- 定时器和标记位
- 触发设置定时器执行,标记位false,不再接受触发设置定时器
- 定时器回调执行,标记位true,后续触发重复上一步
- 返回高阶函数(也可以直接记录时间实现,当前时间 和 上一次记录时间 的差)
实现
function throttle(fn, delay) {
let flag = true;
return function() {
if (flag) {
flag = false;
setTimeout(() => {
fn.apply(this, arguments);
flag = true;
}, delay);
}
}
}
实现shadowCopy
基本类型会产生副本,而引用类型还是共享数据
步骤
- 扩展运算符
...或Object.assign
实现
function shadowCopy(source) {
// return {...source};
return Object.assign(source);
}
实现deepCopy
生成完成独立的副本,不管什么类型数据
步骤
- 创建新对象
- 遍历属性,如果是基本数据类型,直接复制;非基本数据类型,递归调用
- 特殊类型处理:正则,date,函数,symbol,循环引用等
实现
function deepCopy(source) {
// 特殊类型,函数不能处理,null忽略,循环引用报错
// return JSON.parse(JSON.stringify(source));
const getType = obj => {
return Object.prototype.toString.call(obj).slice(8, -1);
}
const getRegExpFlag = re => {
let flags = '';
if(re.global) flags += 'g';
if(re.ignoreCase) flags += 'i';
if(re.multiline) flags += 'm';
return flags
}
// 循环判断,耗性能
const parents = [];
const children = [];
const _clone = parent => {
if (parent === null) return null;
if (typeof parent !== "object") return parent;
let child, proto;
switch getType(parent) {
case 'Array':
child = [];
break;
case 'RegExp':
child = new RegExp(parent.source, getRegExp(parent));
if (parent.lastIndex) child.lastIndex = parent.lastIndex;
break;
case 'Date':
child = new Date(parent.getTime());
break;
default:
proto = Object.getPrototypeOf(parent);
child = Object.create(proto);
}
const index = parents.indexOf(parent);
if (index != -1) { // 已经存在,避免循环,直接返回
return children[index];
}
parents.push(parent);
children.push(child);
for (let i in parent) {
child[i] = _clone(parent[i]);
}
return child;
}
return _clone(parent);
}
实现arrFlat
步骤
- 1、es6自带
flat方法,参数为展开层数 - 2、判断元素是否为数组,递归调用
实现
function flatten(arr, result = []) {
for (let item of arr) {
if (Array.isArray(item))
flatten(item, result)
else
result.push(item)
}
return result
}
// reduce版
const flatten = arr =>
arr.reduce((pre, val) =>
pre.concat(Array.isArray(val) ? flatten(val) : val), []);