1、 new操作符都做了哪些事,手写new操作符
function myNew(func,...args){
//1.创建一个新的空对象
const newObj = {}
//2.将新对象的原型指向构造函数的原型
newObj._proto_ = func.prototype
//3.将构造函数的this指向新对象
let result = apply(newObj,args)
//4.处理构造函数的返回值,根据返回值进行判断,判断是基本类型还是引用类型
return result instanceof Object ? result : newObj
}
2、闭包的理解,手写一个闭包函数使用场景
- 闭包就是能够读取其他函数内部变量的函数
- 闭包是为了设计私有方法和变量,实现js封装
- 函数嵌套函数,内部函数可以访问外部函数的变量
//1.解决for循环问题
for(var i = 0;i<5,i++){
(function(j){
setTimeOut(function(){
console.log(j) // 0 1 2 3 4
},500)
})(i)
}
3、手写防抖和节流函数
- 防抖:应用于搜索框输入、窗口大小调整、表单提交事件
function debonce(func,delay){
let timer = null
return function(...args){
if(timer) clearTimeout(timer);
timer = setTimeout(()=>{
func.apply(this,args) //延迟执行
},delay)
}
}
const searchInput = document.getElementById("myInput")
const fetchData = () => console.log("发送请求")
searchInput.addEventListener("input",debonce(fetchData,500))
- 节流:应用于滚动加载、鼠标移动事件、高频触发事件
function throttle(func,delay){
let timer = null
return function(...args){
if(!timer){
timer = setTimeout(()=>{
func.apply(this,args)
timer = null
},delay)
}
}
}
window.addEventListener("scroll",throttle(()=>{
console.log("滚动加载数据")
},1000))
4、js实现快速排序算法
1.快速排序是一种高效的排序算法,采用分治策略
function quickSort(arr) {
// 如果数组长度小于等于1,直接返回(递归的终止条件)
if (arr.length <= 1) {
return arr;
}
// 选择基准值(pivot),这里选择中间元素
const pivotIndex = Math.floor(arr.length / 2);
const pivot = arr[pivotIndex];
// 定义左右两个数组
const left = [];
const right = [];
// 遍历数组,将元素分配到左右两个数组
for (let i = 0; i < arr.length; i++) {
if (i === pivotIndex) continue; // 跳过基准元素
if (arr[i] < pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
// 递归调用并合并结果
return [...quickSort(left), pivot, ...quickSort(right)];
}
// 使用示例
const unsortedArray = [3, 6, 8, 10, 1, 2, 1];
const sortedArray = quickSort(unsortedArray);
console.log(sortedArray); // 输出: [1, 1, 2, 3, 6, 8, 10]
2.为了更高效地实现快速排序,通常使用Lomuto分区方案,即在数组中选择最后一个元素作为基准值,并通过一次遍历来重新排列数组
function quickSort(arr, left = 0, right = arr.length - 1){
if(left < right){
const pivotIndex = partition(arr, left, right);
quickSort(arr, left, pivotIndex - 1);
quickSort(arr, pivotIndex + 1, right);
}
return arr
}
function partition(arr, left, right){
const pivot = arr[right]; //选择最右边元素作为基准
let i = left;
for(let j = left; j < right; j++){
if(arr[j] < pivot){
[arr[i], arr[j]] = [arr[j], arr[i]]; //交换元素
i++;
}
}
[arr[i], arr[right]] = [arr[right], arr[i]]; //将基准放到正确位置
return i;
}
//使用示例
const array = [3,6,8,10,1,2,1]
quickSort(array);
console.log(array);
5、实现浅拷贝和深拷贝
- 浅拷贝方法
//1.Object.assign()
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = Object.assign({}, obj);
shallowCopy.b.c = 3; // 修改嵌套对象
console.log(obj.b.c); // 3(原对象也被修改)
//2. 扩展运算符 ...
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };
shallowCopy.b.c = 3;
console.log(obj.b.c); // 3(原对象也被修改)
//3.数组的slice()方法
const arr = [1, 2, { a: 3 }];
const shallowCopy = arr.slice();
shallowCopy[2].a = 4;
console.log(arr[2].a); // 4(原数组也被修改)
//4.Array.from()
const arr = [1, 2, { a: 3 }];
const shallowCopy = Array.from(arr);
shallowCopy[2].a = 4;
console.log(arr[2].a); // 4(原数组也被修改)
//5. 使用赋值运算符(=)进行拷贝
const a = [1, 2, 3];
const b = a; // 浅拷贝
b[0] = 4;
console.log(a); // [4, 2, 3]
console.log(b); // [4, 2, 3]
- 深拷贝方法
//1. JSON.parase(JSON.stringify(obj))
const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));
deepCopy.b.c = 3;
console.log(obj.b.c); // 2(原对象不受影响)
缺点:
不能复制 undefined、function、Symbol。
不能处理循环引用(如 obj.self = obj)。
会丢失 Date 对象(转为字符串)。
//2.递归手动实现
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== "object") return obj;
if (hash.has(obj)) return hash.get(obj); // 解决循环引用
const clone = Array.isArray(obj) ? [] : {};
hash.set(obj, clone);
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], hash);
}
}
return clone;
}
// 测试
const obj = { a: 1, b: { c: 2 }, d: [3, 4] };
const deepCopy = deepClone(obj);
deepCopy.b.c = 99;
deepCopy.d.push(5);
console.log(obj); // { a: 1, b: { c: 2 }, d: [3, 4] }(原对象不变)