1.防抖
防抖 —— 触发高频事件后 n 秒后函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间;
function debounce(fn) {
// 创建一个标记用来存放定时器的返回值
let timeout = null;
return function() {
// 每当用户输入的时候把前一个 setTimeout clear 掉
clearTimeout(timeout);
// 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的interval 间隔内如果还有字符输入的话,就不会执行 fn 函数
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, 500)
}
}
// 需要防抖的方法
function sayHi() {
console.log('防抖成功');
}
var inp =document.getElementById('inp');
inp.addEventListener('input', debounce(sayHi)); // 防抖
2.节流
节流 —— 高频事件触发,但在 n 秒内只会执行一次,所以节流会稀释函数的执行频率。
function throttle(fn) {
// 通过闭包保存一个标记
let canRun = true;
return function() {
// 在函数开头判断标记是否为 true,不为 true 则 return
if (!canRun) return;
// 立即设置为 false
canRun = false;
// 将外部传入的函数的执行放在 setTimeout 中
setTimeout(() => {
// 最后在 setTimeout 执行完毕后再把标记设置为 true(关键) 表示可以执行下一次循环了。当定时器没有执行的时候标记永远是 false,在开头被 return 掉
fn.apply(this, arguments);
canRun = true
}, 500)
}
}
// 节流方法
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight)
}
window.addEventListener('resize', throttle(sayHi))
3.深度优先遍历
深度优先遍历 —— 是指从某个顶点出发,首先访问这个顶点,然后找出刚访问 这个结点的第一个未被访问的邻结点,然后再以此邻结点为顶点,继续找它的 下一个顶点进行访问。重复此步骤,直至所有结点都被访问完为止。
//1.深度优先遍历的递归写法
function deepTraversal(node) {
let nodes = [];
if (node != null) {
nodes.push[node];
let childrens = node.children;
for (let i = 0;i < childrens.length; i++) {
deepTraversal(childrens[i]);
}
}
return nodes;
}
//2.深度优先遍历的非递归写法
function deepTraversal(node) {
let nodes = [];
if (node != null) {
let stack = [];
//同来存放将来要访问的节点
stack.push(node);
while (stack.length != 0) {
let item = stack.pop();
//正在访问的节点
nodes.push(item);
let childrens = item.children;
//将现在访问点的节点的子节点存入 stack,供将来访问
for (let i = childrens.length - 1; i >= 0;i--) {
stack.push(childrens[i]);
}
}
}
return nodes;
}
4.广度优先遍历
广度优先遍历 —— 是从某个顶点出发,首先访问这个顶点,然后找出刚访问这个结点所有未被访问的邻结点,访问完后再访问这些结点中第一个邻结点的所有结点,重复此方法,直到所有结点都被访问完为止。
//3.广度优先遍历的递归写法
function wideTraversal(node) {
let nodes = [],
i = 0;
if (node != null) {
nodes.push(node);
wideTraversal(node.nextElementSibling);
node = nodes[i++];
wideTraversal(node.firstElementChild);
}
return nodes;
}
//4.广度优先遍历的非递归写法
function wideTraversal(node) {
let nodes = [],
i = 0;
while (node != null) {
nodes.push(node);
node = nodes[i++];
let childrens = node.children;
for (let i = 0; i < childrens.length; i++) {
nodes.push(childrens[i]);
}
}
return nodes;
}
5.分别用深度优先思想和广度优先思想实现一个拷贝函数
1) 深复制 深度优先遍历 拷贝函数
let DFSdeepClone = (obj, visitedArr = []) => {
let _obj = {};
if (isTypeOf(obj, 'array') || isTypeOf(obj, 'object')) {
let index = visitedArr.indexOf(obj);
_obj = isTypeOf(obj, 'array') ? [] : {};
if (~index) { // 判断环状数据
_obj = visitedArr[index];
} else {
visitedArr.push(obj);
for (let item in obj) {
_obj[item] = DFSdeepClone(obj[item], visitedArr);
}
}
} else if (isTypeOf(obj, 'function')) {
_obj = eval('(' + obj.toString() + ')');
} else {
_obj = obj;
}
return _obj;
}
2) 广度优先遍历 拷贝函数
let BFSdeepClone = (obj) => {
let origin = [obj],
copyObj = {},
copy = [copyObj];
// 去除环状数据
let visitedQueue = [],
visitedCopyQueue = [];
while (origin.length > 0) {
let items = origin.shift(),
_obj = copy.shift();
visitedQueue.push(items);
if (isTypeOf(items, 'object') || isTypeOf(items, 'array')) {
for (let item in items) {
let val = items[item];
if (isTypeOf(val, 'object')) {
let index = visitedQueue.indexOf(val);
if (!~index) {
_obj[item] = {};
//下次 while 循环使用给空对象提供数据
origin.push(val);
// 推入引用对象
copy.push(_obj[item]);
} else {
_obj[item] = visitedCopyQueue[index];
visitedQueue.push(_obj);
}
} else if (isTypeOf(val, 'array')) {
// 数组类型在这里创建了一个空数组
_obj[item] = [];
origin.push(val);
copy.push(_obj[item]);
} else if (isTypeOf(val, 'function')) {
_obj[item] = eval('(' + val.toString() + ')');
} else {
_obj[item] = val;
}
}
// 将已经处理过的对象数据推入数组 给环状数据使用
visitedCopyQueue.push(_obj);
} else if (isTypeOf(items, 'function')) {
copyObj = eval('(' + items.toString() + ')');
} else {
copyObj = obj;
}
}
return copyObj;
}