常用手写代码
debounce防抖
监听一个输入框的,文字变化后触发change事件。 直接用keyup 事件,则会频发触发change事件。
防抖:用户输入结束或暂停时,才会触发change事件
const input1 = document.getElementById("input1 ");
let timer = null;
// input1.addEventListener("keyup ", function () {
// if (timer) {
// clearTimeout(timer);
// }
// timer = setTimeout(() => {
// //模拟触发change 事件
// console.log(input1.value);
// //清空定时器
// timer = null;
// }, 500);
// });
function debounce(fn, delay = 500) {
// timer 是闭包中的
let timer = null;
return function () {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, arguments);
timer = null;
}, delay);
};
}
input1.addEventListener(
"keyup",
debounce(() => {
console.log(input1.value);
}),
600
);
throttle节流
场景:拖拽一个元素时,要随时拿到该元素被拖拽的位置, 直接用drag事件,则会频发触发,很容易导致卡顿。
节流:无论拖拽速度多快,都会每隔100ms触发一次
const div1 = document.getElementById("div1");
//节流 定时器
function throttle(fn, delay = 100) {
let timer = null;
return function () {
if (timer) {
return;
}
timer = setTimeout(() => {
fn.apply(this, arguments);
timer = null;
}, delay);
};
}
div1.addEventListener(
"drag ",
throttle(function (e) {
console.log(e.offsetx, e.offsetY);
})
);
/* 节流 时间戳
function throttle(fn, delay) {
let last = 0;
return function() {
// js在某个数据类型前使用‘+’,这个操作目的是为了将该数据类型转换为Number类型,
// 如果转换失败,则返回NaN;
const now = +new Date();
const offset = now - last;
if (offset > delay) {
last = now;
fn.apply(this, arguments);
}
};
}
*/
isEqual深度比较
function isObject(obj) {
return typeof obj === "object" && obj !== null;
}
function isEqual(obj1, obj2) {
if (!isObject(obj1) || !isObject(obj2)) {
//值类型(注意,参与equal的一般不会是函数)
return obj1 === obj2;
}
if (obj1 === obj2) {
return true;
}
//两个都是对象或数组,而且不相等
// 1。先取出 obj1和 obj2的keys ,比较个数
const obj1Keys = Object.keys(obj1);
const obj2Keys = Object.keys(obj2);
if (obj1Keys.length !== tobj2Keys.length) {
return false;
}
//2.以obj1 为基准,和obj2一次递归比较
for (let key in obj1) {
//比较当前key 的val一递归!!!
const res = isEqual(obj1[key], obj2[key]);
if (!res) {
return false;
}
}
// 3.全相等
return true;
}
//测试
const obj1 = {
a: 100,
b: {
x: 100,
y: 200,
},
};
const obj2 = {
a: 100,
b: {
x: 100,
y: 200,
},
};
flat数组拍平-值类型
function flat(arr) {
//验证arr 中,还有没有深层数组[1,2,[3,4]]
const isDeep = arr.some((item) => item instanceof Array);
if (!isDeep) {
return arr; // 已经是flatern [1,2,3,4]
}
const res = Array.prototype.concat.apply([], arr);
return flat(res); //递归
}
const res = flat([1, 2, [3, 4], 5]);
console.log(res); // [1, 2, 3, 4, 5]
deepClone深拷贝
function deepClone(obj = {}) {
if (typeof obj !== "object" || obj == null) {
// obj是null ,或者不是对象和数组,直接返回
return obj;
}
// 初始化返回结果
let result;
if (obj instanceof Array) {
result = [];
} else {
result = {};
}
for (let key in obj) {
// 保证key 不是原型的属性
if (obj.hasOwnProperty(key)) {
// 递归调用!!!
result[key] = deepClone(obj[key]);
}
}
//返回结果
return result;
}
bind
Function.prototype.band1 = function () {
// 将参数拆解为数组
const args = Array.prototype.slice.call(arguments);
// 获取 this (数组第一项)
const t = args.shift();
// fn1.bind(...) 中的 fn1
const self = this;
return function () {
return self.apply(t, args);
};
};
trim
String.prototype.trim = function () {
return this.replace(/一\s+/, " ").replace(/\s+$/, "");
};
jQuery考虑插件和扩展性
class jQuery {
constructor(selector) {
const result = document.querySelectorAll(selector);
const length = result.length;
for (let i = 0; i < length; i++) {
this[i] = result[i];
}
this.length = length;
this.selector = selector;
}
get(index) {
return this[index];
}
each(fn) {
for (let i = 0; i < this.length; i++) {
const elem = this[i];
fn(elem);
}
}
on(type, fn) {
return this.each((elem) => {
elem.addEventListener(type, fn, false);
});
}
// 扩展很多 DOM API
}
// 插件
jQuery.prototype.dialog = function (info) {
alert(info);
};
// “造轮子”
class myJQuery extends jQuery {
constructor(selector) {
super(selector);
}
// 扩展自己的方法
addClass(className) {}
style(data) {}
}
// const $p = new jQuery('p')
// $p.get(1)
// $p.each((elem) => console.log(elem.nodeName))
// $p.on('click', () => alert('clicked'))