1、防抖节流
防抖:一定时间内,之触发最后一次
节流:一定时间内,只触发第一次
// 防抖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input type="text" id="ipt" />
</body>
</html>
<script>
// 防抖:一定时间内只触发最后一次
let $ipt = document.getElementById("ipt");
$ipt.oninput = debounce(function () {
console.log(this.value);
},500);
// 闭包封装防抖函数
function debounce(fn,delay) {
let t = null;
return function () {
clearTimeout(t);
t = setTimeout(() => {
fn.call(this);
}, delay);
};
}
</script>
// 节流
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div style="height: 5000px"></div>
</body>
</html>
<script>
window.onscroll = throttle(function () {
console.log('节流成功');
},800)
function throttle(fn,delay) {
let flag = true;
return function () {
if (flag) {
setTimeout(() => {
fn.call(this)
flag = true;
}, delay);
}
flag =false
};
}
</script>
2、手写深拷贝
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
</html>
<script>
// 手写深拷贝
let oldObj = {
name: "小铭",
age: 20,
colors: ["blue", "black", "red"],
friend: {
name1: "小红",
name2: "小蓝",
},
};
function deepClone(obj = {}) {
if (typeof obj !== "object" || obj == null) {
return obj;
}
let result;
if (obj instanceof Array) {
result = [];
} else {
result = {};
}
for (key in obj) {
// hasOwnProperty只拷贝对象自身属性(不拷贝原型上的)
if(obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key]);
}
}
return result;
}
let newObj = deepClone(oldObj);
newObj.name = "新名字";
newObj.colors[0] = "yellow";
newObj.friend.name1 = "大红";
console.log(oldObj, "old");
console.log(newObj, "new");
</script>
3、promise封装ajax请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
</html>
<script>
function getJson(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.send();
xhr.onreadystatechange = function () {
// xhr.readyState为4表示请求成功
if (xhr.readyState !== 4) return;
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.responseText);
} else {
reject(new Error(xhr.statusText));
}
// 错误监听函数
xhr.onerror = function () {
reject(new Error(xhr.statusText));
};
// 设置响应数据类型
// xhr.responseType = "json";
};
});
}
let url ='http://demonuxtapi.dishait.cn/mobile/index'
getJson(url).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
</script>
4、手写call、apply、bind函数
// call:改变this指向,立即执行,接收参数以逗号分隔
Function.prototype.myCall = function (ctx, ...args) {
// ctx为上下文,即指向的对象或函数
// this指向调用者的this
// Symbol('fn')保持唯一性 防止调用者有相同名的函数
let fn =Symbol('fn')
ctx[fn] = this
ctx[fn](...args)
delete ctx[fn]
};
function show(...args) {
console.log(this.name, ...args);
}
show.myCall({ name: "myCall111" }, 1, 2, 3);
// apply:改变this指向,立即执行,接收参数为数组
Function.prototype.myApply = function (ctx, args = []) {
if (args && !(args instanceof Array)) {
throw "参数必须为数组";
}
// ctx为上下文,即指向的对象或函数
// this指向调用者的this
// Symbol('fn')保持唯一性 防止调用者有相同名的函数
let fn = Symbol("fn");
ctx.fn = this;
ctx.fn(...args);
delete ctx.fn;
};
function show(...args) {
console.log(this.name, ...args);
}
show.myApply({ name: "myApply" }, [1, 2, 3]);
// bind:不会立即执行,接收参数以逗号分隔,调用后返回一个函数,执行函数时,再传入参会和第一次调用的参数合并
Function.prototype.myBind = function (ctx, ...args) {
// ctx为上下文,即指向的对象或函数
// this指向调用者的this
return (...args2) => {
// Symbol('fn')保持唯一性 防止调用者有相同名的函数
let fn = Symbol("fn");
ctx.fn = this;
ctx.fn(...args.concat(...args2));
delete ctx.fn;
};
};
function show(...args) {
console.log(this.name, ...args);
}
let bindFn = show.myBind({ name: "myBind111" }, 1, 2, 3);
bindFn(4, 5, 6123123);
5、执行顺序判断
// process.nextTick这个名字有点误导,它是在本轮循环执行的,而且是所有微任务里面最快执行的
setTimeout(function () {
console.log(1);
}, 0);
new Promise(function (resolve, reject) {
console.log(2);
resolve();
})
.then(function () {
console.log(3);
})
.then(function () {
console.log(4);
});
process.nextTick(function () {
console.log(5);
});
console.log(6);
执行结果:2、6、5、3、4、1
6、手写promise
// promise特点:
// 1、new Promise是内置构造函数Promise执行一次
// 2、promise的回调函数也会执行一次,这个回调函数给我们提供两个形参(函数)
// 3、promise类的实例没有then方法,应该是原型对象的
function myPromise(callBack) {
let status = "pending";
// 调用promise时自调用一次
// 此时的call指向myPromise,同时myPromise原型上有.then成功与失败的方法
callBack(resolve.bind(this), reject.bind(this));
// 成功回调
function resolve(params) {
status = "success";
// 调用.then成功方法,并将参数传过去
if (this.successCallBack) {
this.successCallBack(params);
}
}
// 失败回调
function reject(err) {
status = "fail";
// 调用.then失败方法,并将参数传过去
if (this.failCallBack) {
this.failCallBack(err);
}
}
}
// 原型添加then方法
myPromise.prototype.then = function (success, fail) {
// .then接收两个参数(函数),参数一成功函数,参数二失败函数
this.successCallBack = success;
this.failCallBack = fail;
};
// 测试使用自定义promise
new myPromise((resolve, reject) => {
setTimeout(() => {
resolve("hi");
reject("error");
}, 1000);
}).then((res) => {
console.log(res, "res");
});
7、数组去重
let arr = [1, 1, 1, 1, 1, 2, 3, 4, 5, 3, 4];
// 1、数组去重方法一
// function arrFn(arrS) {
// let arr =[]
// arrS.forEach(item => {
// if(arr.indexOf(item) === -1) {
// arr.push(item)
// }
// })
// return arr
// }
// let newArr =arrFn(arr)
// 2、数组去重方法二
// let newArr =Array.from(new Set(arr))
// 3、数组去重方法三
function arrFn(arrS) {
let arr = [];
// 这种赋值会出现空元素 如 [empty, 1, 2, 3, 4, 5]
for (val of arrS) {
arr[val] = val;
}
// 去除数组中的空元素
arr = arr.filter((item) => item);
return arr;
}
let newArr = arrFn(arr);
console.log(newArr);